// ==PREPROCESSOR==
// @name "Biography"
// @author "WilB"
// @version "0.9.0.5"
// ==/PREPROCESSOR==

if (!("Version" in utils) || utils.Version < 2310) {fb.ShowPopupMessage("Requires: JScript Panel 2.3.1+", "Biography");}

if (!Array.isArray) {Array.isArray = function(arg) {return Object.prototype.toString.call(arg) === '[object Array]';};}
if (!String.prototype.includes) {String.prototype.includes = function(search, start) {'use strict'; if (typeof start !== 'number') {start = 0;} if (start + search.length > this.length) {return false;} else {return this.indexOf(search, start) !== -1;}};}

Number.prototype.padLeft = function(base, chr) {var len = (String(base || 10).length - String(this).length) + 1; return len > 0 ? new Array(len).join(chr || '0') + this : this;}
String.prototype.clean = function() {return this.replace(/[\/\\|:]/g, "-").replace(/\*/g, "x").replace(/"/g, "''").replace(/[<>]/g, "_").replace(/\?/g, "").replace(/^\./, "_").replace(/\.+$/, "").replace(/^\s+|[\n\s]+$/g, "");}
String.prototype.cut = function() {var n = this.split("(")[0].trim(); return n.length > 3 ? n : this;}
String.prototype.escape = function () {var str = this.replace(/'/g, "''").replace(/[\(\)\[\],%]/g, "'$&'"); if (str.indexOf("$") != -1) {var strSplit = str.split("$"); str = strSplit.join("'$$'");} return str;}
String.prototype.titlecase = function() {
  var smallWords = /^(a|an|and|as|at|but|by|en|for|if|in|nor|of|on|or|per|the|to|vs?\.?|via)$/i; if (this == "N/A") return this;
    return this.replace(/[A-Za-z0-9\u00C0-\u00FF]+[^\s-]*/g, function(match, index, title) {
    // uncomment for smallWord handling: if (index > 0 && index + match.length !== title.length && match.search(smallWords) > -1 && title.charAt(index - 2) !== ":" && (title.charAt(index + match.length) !== '-' || title.charAt(index - 1) === '-') && title.charAt(index - 1).search(/[^\s-]/) < 0) {return match.toLowerCase();}
    if (match.substr(1).search(/[A-Z]|\../) > -1) return match; return match.charAt(0).toUpperCase() + match.substr(1);
  });
}
if (!String.prototype.trim) {String.prototype.trim = function () {return this.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');};}

function userinterface() {
    var custom_col = window.GetProperty("_CUSTOM COLOURS/FONTS: USE", false), lightBg = false, orig_font_sz = 16, orig_font_head_sz = 16, tcol = "", tcol_h = "", style = 1, zoom_font_sz = 16, zoom = 100;
    this.backcol = ""; this.backcoltrans = ""; this.bg = false; this.cust_h_f = []; this.custHeadFont = false; this.dui = window.InstanceType; this.edBg = ""; this.gap = window.GetProperty(" Layout Internal Padding", 20); this.font; this.font_h = 37; this.fontT; this.j_font; this.rndRectBorCol = ""; this.rndRectCol = ""; this.textcol = ""; this.textcol_h = ""; this.textPad = window.GetProperty(" Text Spacing Pad", 0); this.titlecol = ""; this.trans = false;
    var header_cfg = window.GetProperty(" Heading Metrics +/-", "Gap,0,BottomLinePad,0,BtnSize,0,BtnPad,0").replace(/\s+/g, "").split(","); var headerGapAdjust = parseFloat(header_cfg[1]); if (isNaN(headerGapAdjust)) headerGapAdjust = 0; var headerLnAdjust = parseFloat(header_cfg[3]); if (isNaN(headerLnAdjust)) headerLnAdjust = 0;
	var hl = window.GetProperty(" Highlight Colour 0 or 1 [Toggles]", "Btn,0,Heading,1,Line,1,Rim,1,Stars,1,Text,0,Title,1").replace(/\s+/g, "").split(","); this.btnCol = parseFloat(hl[1]); if (isNaN(this.btnCol)) this.btnCol = 0; if (this.btnCol !== 1 && this.btnCol !== 0) this.btnCol = 1; this.headCol = parseFloat(hl[3]); if (isNaN(this.headCol)) this.headCol = 1; if (this.headCol !== 1 && this.headCol !== 0) this.headCol = 1; var lineCol = parseFloat(hl[5]); if (isNaN(lineCol)) lineCol = 1; if (lineCol !== 1 && lineCol !== 0) lineCol = 1; var rimCol = parseFloat(hl[7]); if (isNaN(rimCol)) rimCol = 1; if (rimCol !== 1 && rimCol !== 0) rimCol = 1; var starCol = parseFloat(hl[9]); if (isNaN(starCol)) starCol = 1; if (starCol !== 1 && starCol !== 0) starCol = 1; var textCol = parseFloat(hl[11]); if (isNaN(textCol)) textCol = 0; if (textCol !== 1 && textCol !== 0) textCol = 0; var titleCol = parseFloat(hl[13]); if (isNaN(titleCol)) titleCol = 1; if (titleCol !== 1 && titleCol !== 0) titleCol = 1;
    this.a_rating = window.GetProperty(" Rating Show AllMusic", true); this.bothBio = window.GetProperty("SYSTEM.Both Bio", false); this.bothRev = window.GetProperty("SYSTEM.Both Rev", false); this.l_rating = window.GetProperty(" Rating Show Last.fm", true);
    this.blur_blend = window.GetProperty("SYSTEM.Blur Blend Theme", false); this.blur_dark = window.GetProperty("SYSTEM.Blur Dark Theme", false); this.blur_light = window.GetProperty("SYSTEM.Blur Light Theme", false); var blur_tmp = window.GetProperty("ADV.Image Blur Background Level (0-100)", 90); this.blurLevel = this.blur_blend ? 91.05 - Math.max(Math.min(blur_tmp, 90), 1.05) : Math.max(Math.min(blur_tmp * 2, 254), 0); this.blurAlpha = window.GetProperty("ADV.Image Blur Background Opacity (0-100)", 30); this.blurAlpha = Math.min(Math.max(this.blurAlpha, 0), 100) / 30;
    this.head_font_style = window.GetProperty("SYSTEM.Heading Style", 2); if (this.head_font_style == -1) this.head_font_style =  2; this.title_font_style = window.GetProperty("SYSTEM.Title Style", 1); 
    this.font_head_h = 37; this.heading = window.GetProperty("SYSTEM.Heading", false); this.heading_h = 56; this.head_ln_h = 46; this.srcSizeAdjust = parseFloat(header_cfg[5]); if (isNaN(this.srcSizeAdjust)) this.srcSizeAdjust = 0; this.src_pad = parseFloat(header_cfg[7]); if (isNaN(this.src_pad)) this.src_pad = 0;
    this.local = typeof conf === 'undefined' ? false : true; this.c_c = this.local && typeof opt_c_c !== 'undefined'; window.SetProperty("_CUSTOM COLOURS/FONTS: EMPTY = DEFAULT", "R-G-B (any) or R-G-B-A (not Text...), e.g. 255-0-0")

    this.scrollbar_show = window.GetProperty(" Scrollbar Show", true);
    try {this.scr_type = parseFloat(window.GetProperty(" Scrollbar Type Default-0 Styled-1 Themed-2", "0").replace(/\s+/g, "").charAt(0)); if (isNaN(this.scr_type)) this.scr_type = 0; if (this.scr_type > 2 || this.scr_type < 0) this.scr_type = 0; if (this.scr_type ==2)  window.SetProperty(" Scrollbar Type Default-0 Styled-1 Themed-2", "2 // Scrollbar Settings N/A For Themed"); else window.SetProperty(" Scrollbar Type Default-0 Styled-1 Themed-2", "" + this.scr_type + "");} catch (e) {this.scr_type = 0; window.SetProperty(" Scrollbar Type Default-0 Styled-1 Themed-2", "" + 0 + "");}
    this.scr_col = Math.min(Math.max(window.GetProperty(" Scrollbar Colour Grey-0 Blend-1", 1), 0), 1);
    if (this.scr_type == 2) {this.theme = window.CreateThemeManager("scrollbar"); var im = gdi.CreateImage(21, 21), g = im.GetGraphics(); try {this.theme.SetPartAndStateId(6, 1); this.theme.DrawThemeBackground(g, 0, 0, 21, 50); for (var i = 0; i < 3; i++) {this.theme.SetPartAndStateId(3, i + 1); this.theme.DrawThemeBackground(g, 0, 0, 21, 50);} for (i = 0; i < 3; i++) {this.theme.SetPartAndStateId(1, i + 1); this.theme.DrawThemeBackground(g, 0, 0, 21, 21);}} catch(e) {this.scr_type = 1; window.SetProperty(" Scrollbar Type Default-0 Styled-1 Themed-2", "" + 1 + "");} im.ReleaseGraphics(g); im.Dispose();}
    var themed_w = 21; try {themed_w = utils.GetSystemMetrics(2);} catch (e) {}
    var sbar_w = window.GetProperty(" Scrollbar Size", "Bar,11,Arrow,11,Gap(+/-),0").replace(/\s+/g, "").split(",");
    this.scr_w = parseFloat(sbar_w[1]); if (isNaN(this.scr_w)) this.scr_w = 11; this.scr_w = Math.min(Math.max(this.scr_w, 0), 400);
    var scr_w_o = Math.min(Math.max(window.GetProperty("SYSTEM.Scrollbar Width Bar", 11), 0), 400);
    this.arrow_pad = parseFloat(sbar_w[5]); if (isNaN(this.arrow_pad)) this.arrow_pad = 0; 
    if (this.scr_w != scr_w_o) {this.scr_but_w = parseFloat(sbar_w[3]); if (isNaN(this.scr_but_w)) this.scr_but_w = 11; this.scr_but_w = Math.min(this.scr_but_w, this.scr_w, 400); window.SetProperty(" Scrollbar Size", "Bar," + this.scr_w +",Arrow," + this.scr_but_w + ",Gap(+/-)," + this.arrow_pad);}
    else {this.scr_but_w = parseFloat(sbar_w[3]); if (isNaN(this.scr_but_w)) this.scr_but_w = 11; this.scr_but_w = Math.min(Math.max(this.scr_but_w, 0), 400); this.scr_w = parseFloat(sbar_w[1]); if (isNaN(this.scr_w)) this.scr_w = 11; this.scr_w = Math.min(Math.max(this.scr_w, this.scr_but_w), 400); window.SetProperty(" Scrollbar Size", "Bar," + this.scr_w +",Arrow," + this.scr_but_w + ",Gap(+/-)," + this.arrow_pad);}
    window.SetProperty("SYSTEM.Scrollbar Width Bar", this.scr_w);
    if (this.scr_type == 2) this.scr_w = themed_w; if (!this.scrollbar_show) this.scr_w = 0;
    this.but_h = this.scr_w + (this.scr_type != 2 ? 1 : 0); if (this.scr_type != 2) this.scr_but_w += 1;
    this.sbar_sp = this.scr_w ? this.scr_w + (this.scr_w - this.scr_but_w < 5 || this.scr_type == 2 ? 1 : 0) : 0;
    this.arrow_pad = Math.min(Math.max(-this.but_h / 5, this.arrow_pad), this.but_h / 5);

    var R = function(c) {return c >> 16 & 0xff;}; var G = function(c) {return c >> 8 & 0xff;}; var B = function(c) {return c & 0xff;};
    this.blurChange = function(n) {this.blur_dark = false; this.blur_blend = false; this.blur_light = false; switch (n) {case 2: this.blur_dark = true; break; case 3: this.blur_blend = true; break; case 4: this.blur_light = true; break;} var blur_tmp = window.GetProperty("ADV.Image Blur Background Level (0-100)"); this.blurLevel = this.blur_blend ? 91.05 - Math.max(Math.min(blur_tmp, 90), 1.05) : Math.max(Math.min(blur_tmp * 2, 254), 0); on_colours_changed(true); window.SetProperty("SYSTEM.Blur Blend Theme", this.blur_blend); window.SetProperty("SYSTEM.Blur Dark Theme", this.blur_dark); window.SetProperty("SYSTEM.Blur Light Theme", this.blur_light);}
    var changeBrightness = function (r, g, b, percent){return RGB(Math.min(Math.max(r + (256 - r) * percent / 100, 0), 255), Math.min(Math.max(g + (256 - g) * percent / 100, 0), 255), Math.min(Math.max(b + (256 - b) * percent / 100, 0), 255));}
    var dim = function(col, bg, alpha) {var r = R(col) / 255, g= G(col) / 255, b = B(col) / 255, a = alpha / 255, bgr = R(bg) / 255, bgg = G(bg) / 255, bgb = B(bg) / 255, nR = ((1 - a) * bgr) + (a * r), nG = ((1 - a) * bgg) + (a * g), nB = ((1 - a) * bgb) + (a * b); nR = Math.max(Math.min(Math.round(nR * 255), 255), 0); nG = Math.max(Math.min(Math.round(nG * 255), 255), 0); nB = Math.max(Math.min(Math.round(nB * 255), 255), 0); return RGB(nR, nG, nB);}
    this.get_textselcol = function(c, n, bypass) {var cc = !bypass ? [R(c), G(c), B(c)] : c; var ccc = []; for (var i = 0; i < cc.length; i++) {ccc[i] = cc[i] / 255; ccc[i] = ccc[i] <= 0.03928 ? ccc[i] / 12.92 : Math.pow(((ccc[i] + 0.055 ) / 1.055), 2.4);} var L = 0.2126 * ccc[0] + 0.7152 * ccc[1] + 0.0722 * ccc[2]; if (L > 0.31) return n ? 50 : RGB(0, 0, 0); else return n ? 200 : RGB(255, 255, 255);}
    var set_custom_col = function(c, t) {if (!custom_col) return ""; try {var cc = "", col = []; col = c.split("-"); if (col.length != 3 && col.length != 4) return ""; switch (t) {case 0: cc = RGB(col[0], col[1], col[2]); break; case 1: switch (col.length) {case 3: cc = RGB(col[0], col[1], col[2]); break; case 4: cc = RGBA(col[0], col[1], col[2], col[3]); break;} break;} return cc;} catch(e) {return ""};}
    this.draw = function(gr) {if (this.bg) try {gr.FillSolidRect(0, 0, p.w, p.h, this.backcol)} catch(e) {}}
    this.get_blend = function(c1, c2, f) {var nf = 1 - f, r = (R(c1) * f + R(c2) * nf), g = (G(c1) * f + G(c2) * nf), b = (B(c1) * f + B(c2) * nf); return RGB(r, g, b);}
    this.heading_line = window.GetProperty("SYSTEM.Heading Line Hide-0 Bottom-1 Center-2", 1); if (this.heading_line > 2 || this.heading_line < 0) this.heading_line = 1;
    this.lines = function(gr) {if (!this.c_c) return; try {if (img.artistart && !p.img_only || !img.artistart && !p.img_only && t.text) {gr.DrawRect(0, 0, p.w - 1, p.h - 1, 1, RGB(155, 155, 155)); gr.DrawRect(1, 1, p.w - 3, p.h - 3, 1, RGB(0, 0, 0));}} catch(e) {}}
    this.overlayStyle = window.GetProperty(" Overlay Type Fade|Rect/+Rim|RndRect/+Rim 0-4", 0); if (this.overlayStyle > 4 || this.overlayStyle < 0) this.overlayStyle = 0;
    var fadeSetup = window.GetProperty(" Overlay Setting", "Strength,84.5%,FadeGradient,10%,RimWidth,1px").split(","); this.fadeAlpha = parseFloat(fadeSetup[1]); this.fadeSlope = parseFloat(fadeSetup[3]); if (isNaN(this.fadeAlpha)) this.fadeAlpha = 14.5; this.fadeAlpha =  255 * (100 - this.fadeAlpha) / 100; this.fadeAlpha = Math.max(Math.min(this.fadeAlpha, 255), 0); if (isNaN(this.fadeSlope)) this.fadeSlope = 10; this.fadeSlope /= 10; this.fadeSlope = Math.max(Math.min(this.fadeSlope - 1, 9), -1); if (this.overlayStyle != 2 && this.overlayStyle != 4) this.arc_w = 0; else {this.arc_w = parseFloat(fadeSetup[5]); if (isNaN(this.arc_w)) this.arc_w = 1; this.arc_w = Math.max(Math.min(this.arc_w, 10), 1);}
    var show = window.GetProperty(" Heading Items 0 or 1", "BtnBg,1,BtnName,1,BtnRedLastfm,0,Text,1").replace(/\s+/g, "").split(","); this.BtnBg = parseFloat(show[1]); if (isNaN(this.BtnBg)) this.BtnBg = 1; if (this.BtnBg !== 1 && this.BtnBg !== 0) this.BtnBg = 1; this.BtnName = parseFloat(show[3]); if (isNaN(this.BtnName)) this.BtnName = 1; if (this.BtnName !== 1 && this.BtnName !== 0) this.BtnName = 1; this.lfmTheme = parseFloat(show[5]); if (isNaN(this.lfmTheme)) this.lfmTheme = 0; if (this.lfmTheme !== 1 && this.lfmTheme !== 0) this.lfmTheme = 0; this.headText = parseFloat(show[7]); if (isNaN(this.headText)) this.headText = 0; if (this.headText !== 1 && this.headText !== 0) this.headText = 0;
    this.src = window.GetProperty("SYSTEM.Heading Button Hide-0 Left-1 Right-2", 2); if (this.src < 0 || this.src > 2) this.src = 2;
    this.reset_colors = function () {this.backcol = ""; this.backcoltrans = ""; this.edBg = ""; this.rndRectBorCol = ""; this.rndRectCol = ""; tcol = ""; tcol_h = ""; this.textcol = ""; this.textcol_h = ""; this.titlecol = ""; this.trans = false;}
    var WshShell = new ActiveXObject("WScript.Shell"); try {var dpi = WshShell.RegRead("HKCU\\Control Panel\\Desktop\\WindowMetrics\\AppliedDPI");} catch (e) {var dpi = 120;} this.scale = dpi < 121 ? 1 : dpi / 120; 
    this.run = function(c, w) {try {WshShell.Run(c, w); return true;} catch (e) {return false;}}
    this.browser = function(c) {if (!this.run(c)) fb.ShowPopupMessage("Unable to launch your default browser.", "Biography");}
    this.zoom = function() {return utils.IsKeyPressed(0x10) || utils.IsKeyPressed(0x11);}

    this.get_colors = function() {
        this.backcol = set_custom_col(window.GetProperty("_Custom.Colour Background", ""), 1);
        this.textcol = set_custom_col(window.GetProperty("_Custom.Colour Text", ""), 0);
        this.textcol_h = set_custom_col(window.GetProperty("_Custom.Colour Text Highlight", ""), 0);
        this.backcoltrans = set_custom_col(window.GetProperty("_Custom.Colour Transparent Fill", ""), 1);
        this.blur = this.blur_blend || this.blur_dark || this.blur_light;
        if (this.blur_dark) {this.bg_color_light = RGBA(0, 0, 0, Math.min(160 / this.blurAlpha, 255)); this.bg_color_dark = RGBA(0, 0, 0, Math.min(80 / this.blurAlpha, 255)); if (this.overlayStyle) this.blurOvCol = RGBA(0, 0, 0, 255 - this.fadeAlpha);}
        if (this.blur_light) {this.bg_color_light = RGBA(255, 255, 255, Math.min(160 / this.blurAlpha, 255)); this.bg_color_dark = RGBA(255, 255, 255, Math.min(205 / this.blurAlpha, 255)); if (this.overlayStyle) this.blurOvCol = RGBA(255, 255, 255, 255 - this.fadeAlpha);}
        this.stars = window.GetProperty(" Rating Position Prefer Heading-1 Text-2", 1); if (this.stars < 0 || this.stars > 2) this.stars = 1;
        if ((!this.heading || !this.src) && this.stars == 1) this.stars = 2; if (!this.a_rating && !this.l_rating) this.stars = 0;

        if (this.dui) { // custom colour mapping: DUI colours can be remapped by changing the numbers (0-3)
            if (this.backcol === "") this.backcol = window.GetColourDUI(1);
            tcol = window.GetColourDUI(!textCol ? 0 : 2); tcol_h = window.GetColourDUI(2);
        } else { // custom colour mapping: CUI colours can be remapped by changing the numbers (0-6)
            if (this.backcol === "") this.backcol = window.GetColourCUI(3);
            tcol = window.GetColourCUI(!textCol ? 0 : 2); tcol_h = window.GetColourCUI(2);
        }

        lightBg = this.get_textselcol(this.backcol == 0 ? 0xff000000 : this.backcol, true) == 50;
        if (this.textcol === "") this.textcol = this.blur_blend ? changeBrightness(R(tcol), G(tcol), B(tcol), lightBg ? -10 : 10) : this.blur_dark ? RGB(255, 255, 255) : this.blur_light ? RGB(0, 0, 0) : tcol;
        if (this.textcol_h === "") this.textcol_h = this.blur_blend ? changeBrightness(R(tcol_h), G(tcol_h), B(tcol_h), lightBg ? -10 : 10) : this.blur_dark ? RGB(255, 255, 255) : this.blur_light ? RGB(0, 0, 0) : tcol_h;
        if (window.IsTransparent && this.backcoltrans) {this.bg = true; this.backcol = this.backcoltrans}
        if (!window.IsTransparent || this.dui) this.bg = true; if (this.local) {this.trans = c_trans; this.backcol = c_backcol; this.textcol = this.blur_blend ? changeBrightness(R(c_textcol), G(c_textcol), B(c_textcol), this.get_textselcol(c_backcol == 0 ? 0xff000000 : c_backcol, true) == 50 ? -10 : 10) : this.blur_dark ? RGB(255, 255, 255) : this.blur_light ? RGB(0, 0, 0) : c_textcol; this.textcol_h = this.blur_blend ? changeBrightness(R(c_textcol_h), G(c_textcol_h), B(c_textcol_h), this.get_textselcol(c_backcol == 0 ? 0xff000000 : c_backcol, true) == 50 ? -10 : 10) : this.blur_dark || !this.bg && this.trans && !this.blur_light ? RGB(255, 255, 255) : this.blur_light ? RGB(0, 0, 0) : c_textcol_h;}
        this.ct = this.bg ? this.get_textselcol(this.backcol, true) : 200;
        this.shadow = this.get_textselcol(this.textcol_h, false);
        this.titlecol = this.blur_dark ? RGB(240, 240, 240) : this.blur_light ? RGB(15, 15, 15) : (this.title_font_style == 1 || this.title_font_style == 3) && (this.head_font_style != 1 && this.head_font_style != 3) ? dim(titleCol ? this.textcol_h : this.textcol, !window.IsTransparent ? this.backcol : 0xff000000, 240) : titleCol ? this.textcol_h : this.textcol;
        if (this.stars) {this.rating_icon_on = this.stars == 2 ? RGBA(R(starCol ? this.textcol : this.textcol_h), G(starCol ? this.textcol : this.textcol_h), B(starCol ? this.textcol : this.textcol_h), 232) : this.bg || !this.bg && !this.trans || this.blur_dark || this.blur_light ? RGBA(R(starCol ? this.textcol_h : this.textcol), G(starCol ? this.textcol_h : this.textcol), B(starCol ? this.textcol_h : this.textcol), 232) : RGBA(255, 255, 255, 232); this.rating_icon_off = this.stars == 2 ? RGBA(R(starCol ? this.textcol_h : this.textcol), G(starCol ? this.textcol_h : this.textcol), B(starCol ? this.textcol_h : this.textcol), 60) : this.bg || !this.bg && !this.trans || this.blur_dark || this.blur_light ? RGBA(R(starCol ? this.textcol_h : this.textcol), G(starCol ? this.textcol_h : this.textcol), B(starCol ? this.textcol_h : this.textcol), 60) : RGBA(255, 255, 255, 60); this.rating_icon_border = RGBA(0, 0, 0, 0);}
        this.titlelinecol = this.get_blend(this.blur_dark ? RGB(0, 0, 0) : this.blur_light ? RGB(255, 255, 255) : this.backcol == 0 ? 0xff000000 : this.backcol, lineCol ? this.textcol_h : this.textcol, this.blur ? 0.25 : 0.5);
        this.rndRectCol = set_custom_col(window.GetProperty("_Custom.Colour Overlay Rect & RoundRect", ""), 0);
        this.rndRectBorCol = set_custom_col(window.GetProperty("_Custom.Colour Overlay Rect & RoundRect Rim", ""), 0);
        if (this.rndRectCol === "") this.rndRectCol = this.backcol; this.rndRectCol = RGBA(R(this.rndRectCol), G(this.rndRectCol), B(this.rndRectCol), 255 - this.fadeAlpha);
        if (this.rndRectBorCol === "") {this.rndRectBorCol = rimCol ? this.textcol_h : this.textcol; this.rndRectBorCol = RGBA(R(this.rndRectBorCol), G(this.rndRectBorCol), B(this.rndRectBorCol), 228);}
        this.edBg = (this.blur_dark ? RGB(0, 0, 0) : this.blur_light ? RGB(255, 255, 255) : this.backcol) & 0x99ffffff;
        if (!this.heading) return;
        this.blend1 = this.blur_blend ? this.textcol & RGBA(255, 255, 255, 12) : this.blur_dark || !this.bg && this.trans && !this.blur_light ? RGBA(0, 0, 0, 40) : this.blur_light ? RGBA(0, 0, 0, 15) : this.get_blend(this.backcol == 0 ? 0xff000000 : this.backcol, this.textcol, 0.9);
        this.blend2 = this.blur_blend ? this.textcol & RGBA(255, 255, 255, 12) : this.blur_dark || !this.bg && this.trans && !this.blur_light ? RGBA(0, 0, 0, 40) : this.blur_light ? RGBA(0, 0, 0, 15) : this.get_blend(this.backcol == 0 ? 0xff000000 : this.backcol, this.textcol, this.blur ? 0.75 : 0.82);
        this.blend3 = this.blur_blend ? this.textcol & RGBA(255, 255, 255, 40) : this.blur_dark || !this.bg && this.trans && !this.blur_light ? RGBA(255, 255, 255, 50) : this.blur_light ? RGBA(0, 0, 0, 40) : this.get_blend(this.backcol == 0 ? 0xff000000 : this.backcol, this.textcol, 0.87);
        this.linecol = this.get_blend(this.blur_dark ? RGB(0, 0, 0) : this.blur_light ? RGB(255, 255, 255) : this.backcol == 0 ? 0xff000000 : this.backcol, lineCol ? this.textcol_h : this.textcol, 0.25);
    }
    this.get_colors();

    this.get_font = function() {
        var cust_f = window.GetProperty("_Custom.Font (Name,Size,Style[0-4])", "Segoe UI,16,0");
        if (custom_col && cust_f.length) {cust_f = cust_f.replace(/^[,\s]+|[,\s]+$/g, "").split(","); try {this.font = gdi.Font(cust_f[0], Math.round(parseFloat(cust_f[1])), Math.round(parseFloat(cust_f[2])));} catch(e) {}}
        else if (this.dui) this.font = window.GetFontDUI(3); else this.font = window.GetFontCUI(0);
        try {this.font.Name; this.font.Size; this.font.Style;} catch(e) {this.font = gdi.Font("Segoe UI", 16, 0); p.trace("JScript Panel is unable to use your default font. Using Segoe UI at default size & style instead", false);}
        orig_font_sz = window.GetProperty("SYSTEM.Font Size", 16);
        if (this.font.Size != orig_font_sz) window.SetProperty(" Zoom Font Size (%)", 100);
        orig_font_sz = orig_font_head_sz = this.font.Size; window.SetProperty("SYSTEM.Font Size", this.font.Size);
        zoom = window.GetProperty(" Zoom Font Size (%)", 100); zoom_font_sz = Math.max(Math.round(orig_font_sz * zoom / 100), 1);
        this.font = gdi.Font(this.font.Name, zoom_font_sz, this.font.Style);
        var cust_h_f = window.GetProperty("_Custom.Font Heading (Name,Size,Style[0-4])", "");
        if (custom_col && cust_h_f.length) {this.cust_h_f = cust_h_f.replace(/^[,\s]+|[,\s]+$/g, "").split(","); try {orig_font_head_sz = Math.round(parseFloat(this.cust_h_f[1])) / 1.15; style = Math.round(parseFloat(this.cust_h_f[2])); this.head = gdi.Font(this.cust_h_f[0], orig_font_head_sz, style); this.custHeadFont = true;} catch(e) {orig_font_head_sz = 16; this.head = gdi.Font("Segoe UI", orig_font_head_sz, this.head_font_style); p.trace("JScript Panel is unable to use your heading font. Using Segoe UI at default size instead", false);}}
        else {style = this.head_font_style; this.head = gdi.Font(this.font.name, this.font.Size, style);}
        this.head = gdi.Font(this.head.name, Math.max(Math.round(orig_font_head_sz * zoom / 100 * 1.15), 1), style);
        headerGapAdjust = Math.min(Math.max(headerGapAdjust, -this.gap * 2), this.font.Size * 5); headerLnAdjust = Math.min(Math.max(headerLnAdjust, -this.gap), this.font.Size * 5);
        window.SetProperty(" Zoom Font Size (%)", Math.round(zoom_font_sz / orig_font_sz * 100));
        this.fontT = gdi.Font(this.font.Name, this.font.Size, this.title_font_style); this.j_font = gdi.Font(this.font.Name, this.font.Size * 1.5, 1);
        if (this.local) {this.font = c_font; this.fontT = gdi.Font(this.font.Name, this.font.Size, this.title_font_style); this.j_font = gdi.Font(this.font.Name, this.font.Size * 1.5, 1); if (this.scrollbar_show) {this.scr_type = 0; this.scr_w = c_scr_w; this.scr_but_w = this.scr_w + 1; this.but_h = this.scr_w + 1; this.sbar_sp = this.scr_w +1;}}
        this.calc_text(); p.sizes(); t.art_calc(); t.alb_calc(); but.create_stars(); t.get_widths();
    }

    this.calc_text = function() {
        var i = gdi.CreateImage(1, 1), g = i.GetGraphics();
        this.font_h = Math.round(g.CalcTextHeight("String", this.font) + this.textPad);
        this.font_head_h = g.CalcTextHeight("String", this.head);
        this.head_ln_h = this.heading ? Math.round(this.font_head_h * (this.heading_line == 1 ? 1.25 : 1.1) + (this.heading_line == 1 ? headerLnAdjust : 0)) : 0;
        this.heading_h = this.heading ? Math.round(this.head_ln_h + (this.gap * (this.heading_line == 1 ? 0.75 : 0.25)) + headerGapAdjust) : 0;
        i.ReleaseGraphics(g); i.Dispose();
    }

    this.wheel = function(step) {
        if (!p || (p.mul_item && but.btns["mt"] && but.btns["mt"].trace(p.m_x, p.m_y)) || !p.text_trace) return;
        if (utils.IsKeyPressed(0x11)) {
            zoom_font_sz += step; zoom_font_sz = Math.max(zoom_font_sz, 1);
            this.font = gdi.Font(this.font.Name, zoom_font_sz, this.font.Style);
            this.head = gdi.Font(this.head.name, Math.max(Math.round(orig_font_head_sz * zoom_font_sz / orig_font_sz * 1.15), 1), style);
            this.fontT = gdi.Font(this.font.Name, this.font.Size, this.title_font_style);
            this.j_font = gdi.Font(this.font.Name, this.font.Size * 1.5, 1);
            this.calc_text(); but.create_stars(); t.get_widths(); window.Repaint(); window.SetProperty(" Zoom Font Size (%)", Math.round(zoom_font_sz / orig_font_sz * 100));
            if (p.style < 4) t.toggle(14); else {if (!p.art_ix && img.artistart || !p.alb_ix && !img.artistart) t.grab_text(false); else t.get_multi(false, p.art_ix, p.alb_ix); t.alb_calc(); t.art_calc(); t.paint();}
        }
        if (utils.IsKeyPressed(0x10) && p.style > 3) {
            this.fadeAlpha += (-step * 5); this.fadeAlpha = Math.max(Math.min(this.fadeAlpha, 255), 0);
            window.SetProperty(" Overlay Setting", "Strength," + Math.round((255 - ui.fadeAlpha) / 2.55) + "%,FadeGradient," + fadeSetup[3] + ",RimWidth," + fadeSetup[5]);
            ui.get_colors(); img.resetFade = true; if (!ui.overlayStyle) {img.bp = true; if (img.artistart && p.lfm_img) img.clear_a_rs_cache(); if (!p.art_ix && img.artistart || !p.alb_ix && !img.artistart) img.get_images(); else img.get_multi(p.art_ix);} else t.paint();
        }
    }

	this.htmlParse = function(n, prop, match, func) {
        var ln = n == null ? 0 : n.length, sw = prop ? 0 : 1; var i = 0;
        switch (sw) {
            case 0: while (i < ln) {if (n[i][prop] == match) if (func(n[i]) === true) break; i++;} break;
            case 1: while (i < ln) {if (func(n[i]) === true) break; i++;} break;
        }
    }
}
var ui = new userinterface();

function on_colours_changed(clear) {ui.reset_colors(); ui.get_colors(); img.create_images(); but.create_images(); but.create_mt(); but.refresh(true); if (ui.head && ui.head.Size) but.create_stars(); if (ui.blur_blend || clear) {img.clear_rs_cache(); img.get_images();} t.paint();}
function on_font_changed() {ui.get_font(); alb_scrollbar.reset(); art_scrollbar.reset(); t.on_size(); img.on_size(); window.Repaint();}

function panel_operations() {
    var alb_id = "", alb_id_o = "", artist = "", artist_o = "", g = 0, calc = true, enlarged_img = false, js_stnd = window.GetProperty("ADV.Scrollbar Height Always Full", false), use_local = window.GetProperty("SYSTEM.Use Local", false); js_stnd = !js_stnd ? 2 : 0;
    var bor_l = window.GetProperty(" Layout Outer Padding Image  Left", 20), bor_r = window.GetProperty(" Layout Outer Padding Image  Right", 20), bor_t = window.GetProperty(" Layout Outer Padding Image  Top", 0), bor_b = window.GetProperty(" Layout Outer Padding Image Bottom", 0); this.bor_l = bor_l; this.bor_r = bor_r; this.bor_t = bor_t; this.bor_b = bor_b; this.img_l = 20; this.img_r = 20; this.img_t = 0; this.img_b = 0; this.imgs = 0; this.m_x = 0; this.m_y = 0; this.rel_imgs = window.GetProperty("SYSTEM.Layout Image Size 0-1", 0.7); this.rp_x = 0; this.rp_y = 0; this.rp_w = 0; this.rp_h = 0; topAlign = window.GetProperty(" Text Align Always Top", false), this.sbar_o = 0; this.sbar_x = 0; this.sbar_y = 0; this.sbar_h = 0; this.style = window.GetProperty("SYSTEM.Layout", 0); this.bioStyle = window.GetProperty("SYSTEM.Layout Bio", 0); this.revStyle = window.GetProperty("SYSTEM.Layout Rev", 0); this.text_trace = false; this.text_w = 0; var q = function(s) {return s.split("").reverse().join("");};
    var text_l = window.GetProperty(" Layout Outer Padding Text  Left", 20), text_r = window.GetProperty(" Layout Outer Padding Text  Right", 20), text_t = window.GetProperty(" Layout Outer Padding Text  Top", 20), text_b =window.GetProperty(" Layout Outer Padding Text Bottom", 20);
    var t_l = text_l + ui.arc_w, t_r = text_r + ui.arc_w, t_t = text_t + ui.arc_w, t_b = text_b + ui.arc_w; if (ui.overlayStyle == 2 || ui.overlayStyle == 4) {t_r += 1; t_b += 1;}
    this.autoEnlarge = window.GetProperty("SYSTEM.Image Auto Enlarge", false); this.fs = new ActiveXObject("Scripting.FileSystemObject");

    var box = function(n) {return n != null ? 'Unescape("' + encodeURIComponent(n + "") + '")' : "Empty";}
    this.file = function(f) {return this.fs.fileExists(f);}; this.folder = function(fo) {return this.fs.FolderExists(fo);};
    this.click = function(x, y) {if (ui.zoom()) return; if (t.text && (!this.img_only || this.text_only) && ui.scrollbar_show && x > t.scrollbar_type().x - 10 && x < t.scrollbar_type().x + ui.sbar_sp || ui.heading && t.head && !p.img_only && but.btns["src"] && but.btns["src"].trace(x, y) || but.btns["mt"] && but.btns["mt"].trace(x, y)) return; img.artistart = !img.artistart; if (!this.sameStyle && this.bioStyle != this.revStyle) t.toggle(13); t.na = ""; timer.reset(timer.source, timer.sourcei); but.refresh(); window.SetProperty("SYSTEM.Artist Art", img.artistart); if (calc) calc = img.artistart ? 1 : 2;
    if (!this.art_ix && img.artistart || !this.alb_ix && !img.artistart) {t.grab_text(calc); img.get_images();} else {t.get_multi(calc, this.art_ix, this.alb_ix); img.get_multi(this.art_ix);} if (this.img_only) img.setCrop(true); if (!img.artistart) img.set_chk_arr(null); calc = false;}
    this.create = function(fo) {try {if (!this.folder(fo)) this.fs.CreateFolder(fo);} catch (e) {}}
    this.cyc = window.GetProperty("SYSTEM.Image [Artist] Cycle", true); this.cycle_item = window.GetProperty("SYSTEM.Cycle Time Item", 45); this.cycle_item = Math.max(this.cycle_item, 30); this.cycle_photo = window.GetProperty("SYSTEM.Cycle Time Photo", 15); 
    this.img_only = window.GetProperty("SYSTEM.Image Only", false); this.text_only = window.GetProperty("SYSTEM.Text Only", false); this.h = 0; this.w = 0; var txt_h = this.h;
    this.focus_changed = function(ms) {g++; if (g == 1) {if (!this.img_only) t.on_playback_new_track(); if (!this.text_only || ui.blur) img.on_playback_new_track(); {timer.reset(timer.focus, timer.focusi); timer.focus = window.SetTimeout(function() {g = 0; timer.focus = false;}, ms);} return;} else {timer.reset(timer.focus, timer.focusi); timer.focus = window.SetTimeout(function() {if (!p.img_only) t.on_playback_new_track(); if (!p.text_only || ui.blur) img.on_playback_new_track(); g = 0; timer.focus = false;}, ms);}}
    var InputBox = function(prompt, title, msg) {var vb = new ActiveXObject("ScriptControl"); vb.Language = "VBScript"; var tmp = vb.eval('InputBox(' + [box(prompt), box(title), box(msg)].join(",") + ')'); if (typeof tmp == "undefined") return; if (tmp.length == 254) fb.ShowPopupMessage("Your entry is too long and will be truncated.\n\nEntries are limited to 254 characters.", "Biography"); return tmp.trim();}
    this.ir = function () {return fb.IsPlaying && fb.PlaybackLength <= 0}
    this.item_changed = function(focus, ms) {timer.reset(timer.zSearch, timer.zSearchi); timer.zSearch = window.SetTimeout(function() {p.changed(focus); timer.zSearch = false;}, ms);}
    this.buildFullPth = function(pth) {var tmpFileLoc = "", pattern = /(.*?)\\/gm; while (result = pattern.exec(pth)) {tmpFileLoc = tmpFileLoc.concat(result[0]); try {this.create(tmpFileLoc);} catch(e) {}}}
    this.changed = function(focus) {if (focus) this.getData(false, focus, "multi_tag_jb", 0); else if (this.server) this.getData(false, focus, "", 1);}
    this.cleanMul = function(pth, a, l, focus, bio) {if (typeof focus === 'undefined') focus = this.focus; pth = pth.trim().replace(/\//g, "\\"); if (pth.toLowerCase().indexOf("%profile%") != -1) {var fbPth = fb.ProfilePath.replace(/'/g, "''").replace(/(\(|\)|\[|\]|%|,)/g, "'$1'"); if (fbPth.indexOf("$") != -1) {var fbPthSplit = fbPth.split("$"); fbPth = fbPthSplit.join("'$$'");} pth = pth.replace(/%profile%(\\|)/gi, fbPth);} pth = bio ? this.tfBio(pth, a, focus) : this.tfRev(pth, a, l, focus); if (pth) pth += "\\"; else return ""; var c_pos = pth.indexOf(":"); pth = pth.replace(/[\/|:]/g, "-").replace(/\*/g, "x").replace(/"/g, "''").replace(/[<>]/g, "_").replace(/\?/g, "").replace(/\\\./g, "\\_").replace(/\.+\\/, "\\").replace(/\s*\\\s*/g, "\\"); if(c_pos < 3 && c_pos != -1) pth = replaceAt(pth, c_pos, ":"); return pth.trim();}
    this.cleanPth = function(pth, focus) {if (typeof focus === 'undefined') focus = this.focus; pth = pth.trim().replace(/\//g, "\\"); if (pth.toLowerCase().indexOf("%profile%") != -1) {var fbPth = fb.ProfilePath.replace(/'/g, "''").replace(/(\(|\)|\[|\]|%|,)/g, "'$1'"); if (fbPth.indexOf("$") != -1) {var fbPthSplit = fbPth.split("$"); fbPth = fbPthSplit.join("'$$'");} pth = pth.replace(/%profile%(\\|)/gi, fbPth);} pth = this.eval(pth, focus); if (pth) pth += "\\"; else return ""; var c_pos = pth.indexOf(":"); pth = pth.replace(/[\/|:]/g, "-").replace(/\*/g, "x").replace(/"/g, "''").replace(/[<>]/g, "_").replace(/\?/g, "").replace(/\\\./g, "\\_").replace(/\.+\\/, "\\").replace(/\s*\\\s*/g, "\\"); if(c_pos < 3 && c_pos != -1) pth = replaceAt(pth, c_pos, ":"); return pth.trim();}; this.d = parseFloat(q("0000029142")); this.lfm = q("f50a8f9d80158a0fa0c673faec4584be=yek_ipa&");
    this.eval = function(n, focus) {if (!n) return ""; var tfo = fb.TitleFormat(n); if (typeof focus === 'undefined') focus = this.focus; if (this.ir() && (!focus || this.ir_focus())) {var str = tfo.Eval(); tfo.Dispose(); return str;} var handle = this.handle(focus); if (!handle) {tfo.Dispose(); return "";} var str = tfo.EvalWithMetadb(handle); tfo.Dispose(); return str;}
    this.focus = window.GetProperty("SYSTEM.Prefer Focus", false); this.ir_focus = function() {var pid = -2, fid = plman.GetPlaylistFocusItemIndex(plman.ActivePlaylist), np = plman.GetPlayingItemLocation(); if (np.IsValid) pid = np.PlaylistItemIndex; return fid == pid;}

	var handle_list = fb.CreateHandleList();
	this.upd_handle_list = true;
	this.handle = function(focus) {var handle = fb.IsPlaying && !focus ? fb.GetNowPlaying() : fb.GetFocusItem(); if (!handle) {if (this.upd_handle_list) {handle_list.Dispose(); handle_list = plman.GetPlaylistItems(plman.ActivePlaylist); this.upd_handle_list = false;} if (handle_list.Count) handle = handle_list.Item(0);} return handle;}

    var json_sort = function(data, prop, reverse) {data.sort(function(a, b) {if (!a[prop]) return 1; if (!b[prop]) return -1; a = a[prop].toLowerCase(); b = b[prop].toLowerCase(); if (a < b) return reverse ? 1 : -1; if (a > b) return reverse ? -1 : 1; return 0;}); return data;};
    this.imgText = !window.GetProperty(" Layout Dual Style Auto", true);
    this.json_parse = function(text, prop, test) {if (test) {test = test.split("|"); for (var k in test) {if (text.indexOf(test[k]) != -1) continue; else return false;}} try {var data = JSON.parse(text);} catch (e) {return false;} if (prop) {prop = prop.split("."); for (var k in prop) {if (data === null || typeof data[prop[k]] === 'undefined') return false; data = data[prop[k]];}} return data;}
    this.last_modified = function(filespec) {try {return this.fs.GetFile(filespec).DateLastModified;} catch (e) {}}
    this.leave = function () {if (!this.autoEnlarge || men.right_up) return; if (this.img_only) {this.mode(1); enlarged_img = false;}}
    this.lfm_img = window.GetProperty("SYSTEM.Image [Artist] Prefer Last.fm", true);
    this.mbtn_dn = function(x, y) {switch (true) {case (this.img_only || this.text_only): this.mode(1); break; case !this.text_trace && img.trace(x, y): this.mode(2); break; case this.text_trace: this.mode(3); break;} this.move(x, y, true);}
    this.move = function(x, y, click) {if (this.text_only) this.text_trace = true; else if (this.img_only || !t.text) this.text_trace = false; else if (this.style < 4) {switch (this.style) {case 0: this.text_trace = y > this.img_t + this.imgs; break; case 1: this.text_trace = x < this.w - this.imgs - this.img_r; break; case 2: this.text_trace = y < this.img_t; break; case 3: this.text_trace =  x > this.img_l + this.imgs; break;}} else this.text_trace = y > this.tBoxT && y < this.tBoxT + this.tBoxH && x > this.tBoxL && x < this.tBoxL + this.tBoxW; if (!this.autoEnlarge || click || ui.zoom()) return; var enlarged_img_o = enlarged_img; enlarged_img = !this.text_trace && img.trace(x, y); if (enlarged_img && !this.text_only && !this.img_only && !enlarged_img_o) this.mode(2);}

    var obj_contains = function(arr, p_name) {var k = arr.length; while (k--) if (arr[k].name == p_name) return true; return false;}
    this.paint = function () {window.RepaintRect(this.rp_x, this.rp_y, this.rp_w, this.rp_h);}
    var replaceAt = function(s, n, t) {return s.substring(0, n) + t + s.substring(n + 1);}
    this.removeDiacritics = function (str) {var defaultDiacriticsRemovalMap = [{'base':'A', 'letters':/[\u0041\u24B6\uFF21\u00C0\u00C1\u00C2\u1EA6\u1EA4\u1EAA\u1EA8\u00C3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\u00C4\u01DE\u1EA2\u00C5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F]/g}, {'base':'AA','letters':/[\uA732]/g}, {'base':'AE','letters':/[\u00C6\u01FC\u01E2]/g}, {'base':'AO','letters':/[\uA734]/g}, {'base':'AU','letters':/[\uA736]/g}, {'base':'AV','letters':/[\uA738\uA73A]/g}, {'base':'AY','letters':/[\uA73C]/g}, {'base':'B', 'letters':/[\u0042\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0182\u0181]/g}, {'base':'C', 'letters':/[\u0043\u24B8\uFF23\u0106\u0108\u010A\u010C\u00C7\u1E08\u0187\u023B\uA73E]/g}, {'base':'D', 'letters':/[\u0044\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018B\u018A\u0189\uA779]/g}, {'base':'DZ','letters':/[\u01F1\u01C4]/g}, {'base':'Dz','letters':/[\u01F2\u01C5]/g}, {'base':'E', 'letters':/[\u0045\u24BA\uFF25\u00C8\u00C9\u00CA\u1EC0\u1EBE\u1EC4\u1EC2\u1EBC\u0112\u1E14\u1E16\u0114\u0116\u00CB\u1EBA\u011A\u0204\u0206\u1EB8\u1EC6\u0228\u1E1C\u0118\u1E18\u1E1A\u0190\u018E]/g}, {'base':'F', 'letters':/[\u0046\u24BB\uFF26\u1E1E\u0191\uA77B]/g}, {'base':'G', 'letters':/[\u0047\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E]/g}, {'base':'H', 'letters':/[\u0048\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D]/g}, {'base':'I', 'letters':/[\u0049\u24BE\uFF29\u00CC\u00CD\u00CE\u0128\u012A\u012C\u0130\u00CF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197]/g}, {'base':'J', 'letters':/[\u004A\u24BF\uFF2A\u0134\u0248]/g}, {'base':'K', 'letters':/[\u004B\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2]/g}, {'base':'L', 'letters':/[\u004C\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780]/g}, {'base':'LJ','letters':/[\u01C7]/g}, {'base':'Lj','letters':/[\u01C8]/g}, {'base':'M', 'letters':/[\u004D\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C]/g}, {'base':'N', 'letters':/[\u004E\u24C3\uFF2E\u01F8\u0143\u00D1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u0220\u019D\uA790\uA7A4]/g}, {'base':'NJ','letters':/[\u01CA]/g}, {'base':'Nj','letters':/[\u01CB]/g}, {'base':'O', 'letters':/[\u004F\u24C4\uFF2F\u00D2\u00D3\u00D4\u1ED2\u1ED0\u1ED6\u1ED4\u00D5\u1E4C\u022C\u1E4E\u014C\u1E50\u1E52\u014E\u022E\u0230\u00D6\u022A\u1ECE\u0150\u01D1\u020C\u020E\u01A0\u1EDC\u1EDA\u1EE0\u1EDE\u1EE2\u1ECC\u1ED8\u01EA\u01EC\u00D8\u01FE\u0186\u019F\uA74A\uA74C]/g}, {'base':'OI','letters':/[\u01A2]/g}, {'base':'OO','letters':/[\uA74E]/g}, {'base':'OU','letters':/[\u0222]/g}, {'base':'P', 'letters':/[\u0050\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754]/g}, {'base':'Q', 'letters':/[\u0051\u24C6\uFF31\uA756\uA758\u024A]/g}, {'base':'R', 'letters':/[\u0052\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782]/g}, {'base':'S', 'letters':/[\u0053\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784]/g}, {'base':'T', 'letters':/[\u0054\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786]/g}, {'base':'TZ','letters':/[\uA728]/g}, {'base':'U', 'letters':/[\u0055\u24CA\uFF35\u00D9\u00DA\u00DB\u0168\u1E78\u016A\u1E7A\u016C\u00DC\u01DB\u01D7\u01D5\u01D9\u1EE6\u016E\u0170\u01D3\u0214\u0216\u01AF\u1EEA\u1EE8\u1EEE\u1EEC\u1EF0\u1EE4\u1E72\u0172\u1E76\u1E74\u0244]/g}, {'base':'V', 'letters':/[\u0056\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245]/g}, {'base':'VY','letters':/[\uA760]/g}, {'base':'W', 'letters':/[\u0057\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72]/g}, {'base':'X', 'letters':/[\u0058\u24CD\uFF38\u1E8A\u1E8C]/g}, {'base':'Y', 'letters':/[\u0059\u24CE\uFF39\u1EF2\u00DD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE]/g}, {'base':'Z', 'letters':/[\u005A\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762]/g}, {'base':'a', 'letters':/[\u0061\u24D0\uFF41\u1E9A\u00E0\u00E1\u00E2\u1EA7\u1EA5\u1EAB\u1EA9\u00E3\u0101\u0103\u1EB1\u1EAF\u1EB5\u1EB3\u0227\u01E1\u00E4\u01DF\u1EA3\u00E5\u01FB\u01CE\u0201\u0203\u1EA1\u1EAD\u1EB7\u1E01\u0105\u2C65\u0250]/g}, {'base':'aa','letters':/[\uA733]/g}, {'base':'ae','letters':/[\u00E6\u01FD\u01E3]/g}, {'base':'ao','letters':/[\uA735]/g}, {'base':'au','letters':/[\uA737]/g}, {'base':'av','letters':/[\uA739\uA73B]/g}, {'base':'ay','letters':/[\uA73D]/g}, {'base':'b', 'letters':/[\u0062\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253]/g}, {'base':'c', 'letters':/[\u0063\u24D2\uFF43\u0107\u0109\u010B\u010D\u00E7\u1E09\u0188\u023C\uA73F\u2184]/g}, {'base':'d', 'letters':/[\u0064\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\uA77A]/g}, {'base':'dz','letters':/[\u01F3\u01C6]/g}, {'base':'e', 'letters':/[\u0065\u24D4\uFF45\u00E8\u00E9\u00EA\u1EC1\u1EBF\u1EC5\u1EC3\u1EBD\u0113\u1E15\u1E17\u0115\u0117\u00EB\u1EBB\u011B\u0205\u0207\u1EB9\u1EC7\u0229\u1E1D\u0119\u1E19\u1E1B\u0247\u025B\u01DD]/g}, {'base':'f', 'letters':/[\u0066\u24D5\uFF46\u1E1F\u0192\uA77C]/g}, {'base':'g', 'letters':/[\u0067\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\u1D79\uA77F]/g}, {'base':'h', 'letters':/[\u0068\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265]/g}, {'base':'hv','letters':/[\u0195]/g}, {'base':'i', 'letters':/[\u0069\u24D8\uFF49\u00EC\u00ED\u00EE\u0129\u012B\u012D\u00EF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131]/g}, {'base':'j', 'letters':/[\u006A\u24D9\uFF4A\u0135\u01F0\u0249]/g}, {'base':'k', 'letters':/[\u006B\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3]/g}, {'base':'l', 'letters':/[\u006C\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747]/g}, {'base':'lj','letters':/[\u01C9]/g}, {'base':'m', 'letters':/[\u006D\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F]/g}, {'base':'n', 'letters':/[\u006E\u24DD\uFF4E\u01F9\u0144\u00F1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5]/g}, {'base':'nj','letters':/[\u01CC]/g}, {'base':'o', 'letters':/[\u006F\u24DE\uFF4F\u00F2\u00F3\u00F4\u1ED3\u1ED1\u1ED7\u1ED5\u00F5\u1E4D\u022D\u1E4F\u014D\u1E51\u1E53\u014F\u022F\u0231\u00F6\u022B\u1ECF\u0151\u01D2\u020D\u020F\u01A1\u1EDD\u1EDB\u1EE1\u1EDF\u1EE3\u1ECD\u1ED9\u01EB\u01ED\u00F8\u01FF\u0254\uA74B\uA74D\u0275]/g}, {'base':'oi','letters':/[\u01A3]/g}, {'base':'ou','letters':/[\u0223]/g}, {'base':'oo','letters':/[\uA74F]/g}, {'base':'p','letters':/[\u0070\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755]/g}, {'base':'q','letters':/[\u0071\u24E0\uFF51\u024B\uA757\uA759]/g}, {'base':'r','letters':/[\u0072\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783]/g}, {'base':'s','letters':/[\u0073\u24E2\uFF53\u00DF\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B]/g}, {'base':'t','letters':/[\u0074\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787]/g}, {'base':'tz','letters':/[\uA729]/g}, {'base':'u','letters':/[\u0075\u24E4\uFF55\u00F9\u00FA\u00FB\u0169\u1E79\u016B\u1E7B\u016D\u00FC\u01DC\u01D8\u01D6\u01DA\u1EE7\u016F\u0171\u01D4\u0215\u0217\u01B0\u1EEB\u1EE9\u1EEF\u1EED\u1EF1\u1EE5\u1E73\u0173\u1E77\u1E75\u0289]/g}, {'base':'v','letters':/[\u0076\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C]/g}, {'base':'vy','letters':/[\uA761]/g}, {'base':'w','letters':/[\u0077\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73]/g}, {'base':'x','letters':/[\u0078\u24E7\uFF58\u1E8B\u1E8D]/g}, {'base':'y','letters':/[\u0079\u24E8\uFF59\u1EF3\u00FD\u0177\u1EF9\u0233\u1E8F\u00FF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF]/g}, {'base':'z','letters':/[\u007A\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763]/g}]; for (var i = 0; i < defaultDiacriticsRemovalMap.length; i++) str = str.replace(defaultDiacriticsRemovalMap[i].letters, defaultDiacriticsRemovalMap[i].base); return str;}
    this.save = function(n, l) {try {return utils.WriteTextFile(n, l);} catch (e) {return false;}}
    this.server = true; window.NotifyOthers("not_server_jb", 0);
    this.setBorder = function(imgFull, bor) {if (imgFull) {this.bor_l = 0; this.bor_r = bor > 1 ? 10 : 0; this.bor_t = 0; this.bor_b = bor > 1 ? 10 : 0;} else {this.bor_l = bor_l; this.bor_r = bor < 2 ? bor_r : Math.max(bor_r, 10); this.bor_t = bor_t; this.bor_b = bor < 2 ? bor_b : Math.max(bor_b, 10);}}
    this.setCycItem = function(n) {var ns = InputBox("Enter time in seconds\n\nMinimum = 30 seconds", "Item: Cycle Time", this.cycle_item); if (!ns || ns == this.cycle_item) return false; else {this.cycle_item = Math.round(ns); if (!this.cycle_item || isNaN(this.cycle_item)) this.cycle_item = 30; this.cycle_item = Math.max(this.cycle_item, 30); window.SetProperty("SYSTEM.Cycle Time Item", this.cycle_item);}}
    this.setCycPhoto = function() {var ns = InputBox("\n\nEnter time in seconds", "Photo: Cycle Time", this.cycle_photo); if (!ns || ns == this.cycle_photo) return false; else {this.cycle_photo = Math.round(ns); if (!this.cycle_photo || isNaN(this.cycle_photo)) this.cycle_photo = 15; window.SetProperty("SYSTEM.Cycle Time Photo", this.cycle_photo);}}
    this.tfBio = function(n, a, focus) {try{n = n.replace(/((\$if|\$and|\$or|\$not|\$xor)(|\d)\(|\[)[^$%]*%bio_artist%/gi, "$&#@!%path%#@!").replace(/%bio_artist%/gi, a.escape()).replace(/%bio_album%/gi, this.l_tf); n = this.eval(n, focus); n = n.replace(/#@!.*?#@!/g, "");} catch (e) {return "";} return n;}
    this.tfRev = function(n, aa, l, focus) {try {n = n.replace(/((\$if|\$and|\$or|\$not|\$xor)(|\d)\(|\[)[^$%]*(%bio_albumartist%|%bio_album%)/gi, "$&#@!%path%#@!").replace(/%bio_albumartist%/gi, aa.escape()).replace(/%bio_album%/gi, l.escape()); n = this.eval(n, focus); n = n.replace(/#@!.*?#@!/g, "");} catch (e) {return "";} return n;}
    this.trace = function(message, n) {var trace = true; if (trace) console.log("Biography" + (n ? " Server" : "") + ": " + message);}
    var yttm = fb.ProfilePath + "yttm\\"; this.create(yttm); this.bio_ini = yttm + "biography_jsp.ini";
    
    this.def_dn = [
        {name:"Biography [Allmusic] Auto-Fetch", dn:1},
        {name:"Biography [Lastfm] Auto-Fetch", dn:1},
        {name:"Album Review [Allmusic] Auto-Fetch", dn:1},
        {name:"Album Review [Lastfm] Auto-Fetch", dn:1},
        {name:"Image [Artist] Auto-Fetch", dn:1},
        {name:"Image [Review] Auto-Fetch", dn:1}
    ];
    var def_paths = [
        {name:"Album Review [Allmusic] Folder", path:"%profile%\\yttm\\review\\allmusic\\$lower($cut(%BIO_ALBUMARTIST%,1))"},
        {name:"Album Review [Lastfm] Folder",path:"%profile%\\yttm\\review\\lastfm\\$lower($cut(%BIO_ALBUMARTIST%,1))"},
        {name:"Biography [Allmusic] Folder", path:"%profile%\\yttm\\biography\\allmusic\\$lower($cut(%BIO_ARTIST%,1))"},
        {name:"Biography [Lastfm] Folder", path:"%profile%\\yttm\\biography\\lastfm\\$lower($cut(%BIO_ARTIST%,1))"},
        {name:"Image [Artist] Folder", path:"%profile%\\yttm\\art_img\\$lower($cut(%BIO_ARTIST%,1))\\%BIO_ARTIST%"},
        {name:"Image [Review] Folder", path:"%profile%\\yttm\\rev_img\\$lower($cut(%BIO_ALBUMARTIST%,1))\\%BIO_ALBUMARTIST%"}
    ];
    this.cov = [
        {name:"Auto-Save", path:0},
        {name:"Auto-Save Folder", path:"$directory_path(%path%)"},
        {name:"Auto-Save File Name", path:"cover"}
    ];
    this.def_tf = [
        {name:"%BIO_ALBUMARTIST%", tf:"$if3($meta(album artist,0),$meta(artist,0),$meta(composer,0),$meta(performer,0))"},
        {name:"%BIO_ARTIST%", tf:"$if3($meta(artist,0),$meta(album artist,0),$meta(composer,0),$meta(performer,0))"},
        {name:"%BIO_ALBUM%", tf:"$meta(album,0)"},
        {name:"Album Name Auto-Clean", tf:0},
        {name:"Cache Expiry (days: minimum 28)", tf:28},
        {name:"Image [Artist] Initial Fetch Number (1-20)", tf:5},
        {name:"Image [Artist] Auto-Add New", tf:1},
        {name:"Image [Artist] Cache Limit", tf:""},
        {name:"Mouse Left Button Click: Map To Double-Click", tf:0},
        {name:"Search: Include Partial Matches", tf:1},
        {name:"Various Artists", tf:"Various Artists"}
    ];
    this.lang = [
        {name:"Lastfm Language", tf:"EN"},
        {name:"Lastfm Language Fallback To English", tf:0}
    ];
    var advCov = [
        {name:"Image [Cover] Check Custom Paths", path:0},
        {name:"Image [Cover] Custom Path 1 [Full Path Minus Extension]", path:""},
        {name:"Image [Cover] Custom Path 2 [Full Path Minus Extension]", path:""},
        {name:"Image [Cover] Custom Path 3 [Full Path Minus Extension]", path:""},
        {name:"Image [Cover] Custom Path 4 [Full Path Minus Extension]", path:""},
        {name:"Image [Cover] Custom Path 5 [Full Path Minus Extension]", path:""}
    ];
    var advMore = [
        {name:"Use Supplemental Cache", path:0},
        {name:"Supplemental Cache [Use Find>Replace on SAVE paths]", path:"yttm>yttm\\bio_supplemental"},
        {name:"Review Image Quality 0-Medium 1-High", path:0},
        {name:"Similar Artists: Number to Display(0-10)", path:4}
    ];
    var advSimilar = [
        {name:"Save List 0-Never 1-Auto", tag:1},
        {name:"Save Folder", tag:"%profile%\\yttm\\lastfm\\$lower($cut(%BIO_ARTIST%,1))"}
    ];
    var advTag = [
        {name:"Write Tag: Album Genre AllMusic", tag:1},
        {name:"Write Tag: Album Mood AllMusic", tag:1},
        {name:"Write Tag: Album Rating AllMusic", tag:1},
        {name:"Write Tag: Album Theme AllMusic", tag:1},
        {name:"Write Tag: Artist Genre AllMusic", tag:1},
        {name:"Write Tag: Album Genre Last.fm", tag:1},
        {name:"Write Tag: Artist Genre Last.fm", tag:1},
        {name:"Write Tag: Similar Artists Last.fm: Number to Write (0-100)", tag:4},
        {name:"Tag Name: Album Genre AllMusic", tag:"Album Genre AllMusic"},
        {name:"Tag Name: Album Mood AllMusic", tag:"Album Mood AllMusic"},
        {name:"Tag Name: Album Rating AllMusic", tag:"Album Rating AllMusic"},
        {name:"Tag Name: Album Theme AllMusic", tag:"Album Theme AllMusic"},
        {name:"Tag Name: Artist Genre AllMusic", tag:"Artist Genre AllMusic"},
        {name:"Tag Name: Album Genre Last.fm", tag:"Album Genre Last.fm"},
        {name:"Tag Name: Artist Genre Last.fm", tag:"Artist Genre Last.fm"},
        {name:"Tag Name: Similar Artists Last.fm", tag:"Similar Artists Last.fm"}
    ];
    var helpText = "A foobar2000 restart is required for any changes to take effect. Only change entries after the equal signs. Entries have a 255 character limit.\r\n\r\n"
        + "INI Version: JScript Panel\r\n\r\n"
        + "========================================\r\n"
        + "CUSTOMISATION HELP:\r\n\r\nEnter 0 or 1 or as indicated.\r\n\r\n"
        + "AUTO-FETCH:\r\n1 Enable web search for source. Results are cached.\r\n0 Disable web search for source. Existing data cached to disc will be loaded.\r\n\r\n"
        + "NAMES:\r\nUsed in search, folder + file names & headings. %BIO_ALBUMARTIST%, %BIO_ARTIST% and %BIO_ALBUM% define titleformat used for albumartist, artist and album, respectively. Variables are specific to JScript Biography. Change default title formatting if required.\r\n\r\n"
        + "SAVE:\r\nEnter title formatting or absolute paths. Always use the variables %BIO_ALBUMARTIST%, %BIO_ARTIST% or %BIO_ALBUM%, if applicable, to ensure correct functionality (copy style of defaults). The 2 reviews (& 2 biographies) must be saved in different folders. %profile% can be put at the start of the path and resolves to the foobar2000 profile folder or program folder in portable mode. Don't use %path% here - it's incompatible with radio streams etc. As with title formatting, enclose literal ()[]'%$ in single quotes. It is recommended to validate changes by checking save paths of a few files. Trailing \\ not needed. File names are auto generated. To organise by artist instead of source, search documentation for SAVE & paste patterns therein.\r\n\r\n"
        + "COVERS: MUSIC FILES:\r\nEnable auto-save to have music file covers saved to a specified location.\r\n\r\n"
        + "LASTFM LANGUAGE:\r\nEnter language code: EN, DE, ES, FR, IT, JA, PL, PT, RU, SV, TR or ZH, or use \"Sources Menu\". Optional fallback to trying English (EN) server if no results. AllMusic info is only available in English.\r\n\r\n"
        + "MISCELLANEOUS:\r\nImage [Artist] Cache Limit: limits number of images stored to value set. If used with \"Auto-Add New\", newer images are added & older removed to give a fixed number of up-to-date images.\r\n\r\n"
        + "ADVANCED:\r\nCustom cover paths. Most users shouldn't need this feature as covers are auto-loaded via foobar2000 album art reader or from save locations. Enable if required.\r\nSimilar Artists (\"Tagger\" & \"More Menu\"). Up to 4 are read from the biography. Using 5+ requires a saved list. Saving auto-enables by default while either set to 5+.\r\nWrite Tag: sets which tags are available to be written. Enter 0 or 1 or as indicated. Change tag names as required.\r\n***See documentation for full info on advanced items.***"

	if (!this.file(this.bio_ini)) {
		utils.WriteINI(this.bio_ini, helpText, "", "=======================================\r\n");
		for (i = 0; i < this.def_dn.length; i++) utils.WriteINI(this.bio_ini, "AUTO-FETCH", this.def_dn[i].name, this.def_dn[i].dn + (i == this.def_dn.length - 1 ? "\r\n" : ""));
		for (i = 0; i < 3; i++) utils.WriteINI(this.bio_ini, "NAMES", this.def_tf[i].name, this.def_tf[i].tf + (i == 2 ? "\r\n" : ""));
		for (i = 0; i < def_paths.length; i++) utils.WriteINI(this.bio_ini, "SAVE", def_paths[i].name, def_paths[i].path + (i == def_paths.length - 1 ? "\r\n" : ""));
		for (i = 0; i < this.cov.length; i++) utils.WriteINI(this.bio_ini, "COVERS: MUSIC FILES", this.cov[i].name, this.cov[i].path + (i == this.cov.length - 1 ? "\r\n" : ""));
		for (i = 0; i < this.lang.length; i++) utils.WriteINI(this.bio_ini, "LASTFM LANGUAGE", this.lang[i].name, this.lang[i].tf + (i == this.lang.length - 1 ? "\r\n" : ""));
		for (i = 3; i < this.def_tf.length; i++) utils.WriteINI(this.bio_ini, "MISCELLANEOUS", this.def_tf[i].name, this.def_tf[i].tf + (i == this.def_tf.length - 1 ? "\r\n" : ""));
		for (i = 0; i < advCov.length; i++) utils.WriteINI(this.bio_ini, "ADVANCED: CUSTOM COVER PATHS", advCov[i].name, advCov[i].path + (i == advCov.length - 1 ? "\r\n" : ""));
		for (i = 0; i < advMore.length; i++) utils.WriteINI(this.bio_ini, "ADVANCED: MORE MENU ITEMS", advMore[i].name, advMore[i].path + (i == advMore.length - 1 ? "\r\n" : ""));
		for (i = 0; i < advSimilar.length; i++) utils.WriteINI(this.bio_ini, "ADVANCED: SIMILAR ARTISTS", advSimilar[i].name, advSimilar[i].tag + (i == advSimilar.length - 1 ? "\r\n" : ""));
		for (i = 0; i < advTag.length; i++) utils.WriteINI(this.bio_ini, "ADVANCED: TAG WRITER", advTag[i].name, advTag[i].tag);
	}

    var pth_arr = ["amRevPth", "lfmRevPth", "amBioPth", "lfmBioPth", "imgArtPth", "imgCovPth", "imgCovFn", "lfmSimPth"];
    var tf_arr = ["aa_tf", "a_tf", "l_tf"]; for (i = 0; i < tf_arr.length; i++) {this[tf_arr[i]] = utils.ReadINI(this.bio_ini, "NAMES", this.def_tf[i].name).replace(RegExp(this.def_tf[i].name, "gi"), ""); if (!this[tf_arr[i]].length) this[tf_arr[i]] = this.def_tf[i].tf; for (j = 0; j < 3; j++) this[tf_arr[i]] = this[tf_arr[i]].replace(RegExp(this.def_tf[j].name, "gi"), utils.ReadINI(this.bio_ini, "NAMES", this.def_tf[j].name));}
    for (i = 0; i < 5; i++) {this[pth_arr[i]] = utils.ReadINI(this.bio_ini, "SAVE", def_paths[i].name); if (!this[pth_arr[i]]) this[pth_arr[i]] = def_paths[i].path;}
    for (i = 5; i < 7; i++) {this[pth_arr[i]] = utils.ReadINI(this.bio_ini, "COVERS: MUSIC FILES", this.cov[i - 4].name); if (!this[pth_arr[i]]) this[pth_arr[i]] = this.cov[i - 4].path;}
    this[pth_arr[7]] = utils.ReadINI(this.bio_ini, "ADVANCED: SIMILAR ARTISTS", advSimilar[1].name); if (!this[pth_arr[7]]) this[pth_arr[7]] = advSimilar[1].tag;
    for (i = 0; i < pth_arr.length; i++) {for (j = 0; j < 3; j++) this[pth_arr[i]] = this[pth_arr[i]].replace(RegExp(this.def_tf[j].name, "gi"), this[tf_arr[j]]);}
    this.dbl_click = parseFloat(utils.ReadINI(this.bio_ini, "MISCELLANEOUS", this.def_tf[8].name)); if (this.dbl_click !== 1 && this.dbl_click !== 0) this.dbl_click = this.def_tf[8].tf;
    this.va = utils.ReadINI(this.bio_ini, "MISCELLANEOUS", this.def_tf[10].name); if (!this.va.length) this.va = this.def_tf[10].tf; this.va = this.va.toLowerCase();
    var artFieldsArr = [], inBio = [false, false, true, true, true, false, false], init_albums = [], init_artists = [], inRev = [true, true, false, false, false, true, true]; pth_arr = ["amRevMul", "lfmRevMul", "amBioMul", "lfmBioMul", "imgArtMul", "imgRevMul"]; this.mul_item = window.GetProperty("SYSTEM.Button More Items", false);
    for (i = 0; i < pth_arr.length; i++) {/*mul*/this[pth_arr[i]] = utils.ReadINI(this.bio_ini, "SAVE", def_paths[i].name); if (!this[pth_arr[i]]) this[pth_arr[i]] = def_paths[i].path; if (inRev[i]) this[pth_arr[i]] = this[pth_arr[i]].replace(/%BIO_ALBUMARTIST%|%BIO_ARTIST%/gi, "%BIO_ALBUMARTIST%"); if (inBio[i]) this[pth_arr[i]] = this[pth_arr[i]].replace(/%BIO_ARTIST%|%BIO_ALBUMARTIST%/gi, "%BIO_ARTIST%");}
    this.rev_img = parseFloat(utils.ReadINI(this.bio_ini, "AUTO-FETCH", this.def_dn[5].name)); if (this.rev_img !== 1 && this.rev_img !== 0) this.rev_img = this.def_dn[5].dn;
    pth_arr = ["supCache", "imgRevHQ"]; for (i = 0; i < pth_arr.length; i++) this[pth_arr[i]] = parseFloat(utils.ReadINI(this.bio_ini, "ADVANCED: MORE MENU ITEMS", advMore[i * 2].name)); if (this[pth_arr[i]] !== 1 && this[pth_arr[i]] !== 0) this[pth_arr[i]] = advMore[0 * 2].path;
    var similarNo = parseFloat(utils.ReadINI(this.bio_ini, "ADVANCED: MORE MENU ITEMS", advMore[3].name)); similarNo = Math.min(Math.max(similarNo, 0), 10);
    var tag_arr = ["albGenre_am", "mood", "rating", "theme", "artGenre_am", "albGenre_lfm", "artGenre_lfm", "similar"]; for (i = 0; i < tag_arr.length; i++) {this[tag_arr[i]] = parseFloat(utils.ReadINI(this.bio_ini, "ADVANCED: TAG WRITER", advTag[i].name));  if (i < tag_arr.length - 1) {if (this[tag_arr[i]] !== 1 && this[tag_arr[i]] !== 0) this[tag_arr[i]] = advTag[i].tag;} else {this[tag_arr[i]] = Math.min(Math.max(this[tag_arr[i]], 0), 100);}}
    var tag_nm = ["albGenre_am_nm", "mood_nm", "rating_nm", "theme_nm", "artGenre_am_nm", "albGenre_lfm_nm", "artGenre_lfm_nm", "similar_nm"]; for (i = 0; i < tag_nm.length; i++) {this[tag_nm[i]] = utils.ReadINI(this.bio_ini, "ADVANCED: TAG WRITER", advTag[i + 8].name); if (!this[tag_nm[i]]) this[tag_nm[i]] = advTag[i + 8].tag;}
    this.lfm_sim = parseFloat(utils.ReadINI(this.bio_ini, "ADVANCED: SIMILAR ARTISTS", advSimilar[0].name)); if (this.lfm_sim !== 1 && this.lfm_sim !== 0) this.lfm_sim = advSimilar[0].tag; if (this.lfm_sim && similarNo < 5 && this.similar < 5) this.lfm_sim = 0; if (this.file("C:\\check_local\\1450343922.txt")) {this.lfm_sim = 0; this.imgRevHQ = 1; this.supCache = 1;}
    if (this.supCache) {
        pth_arr = ["amRevSup", "lfmRevSup", "amBioSup", "lfmBioSup", "imgArtSup", "imgRevSup"]; var arr1 = [], arr2 = [], rep = "", replace = utils.ReadINI(this.bio_ini, "ADVANCED: MORE MENU ITEMS", advMore[1].name).split("|");
        for (i = 0; i < replace.length; i++) {rep = replace[i].split(">"); arr1.push(rep[0] ? rep[0].trim() : "yttm"); arr2.push(rep[1] ? rep[1].trim() : "yttm\\bio_supplemental");} for (i = 0; i < pth_arr.length; i++) {this[pth_arr[i]] = utils.ReadINI(this.bio_ini, "SAVE", def_paths[i].name); if (arr1.length == arr2.length) for (j = 0; j < arr1.length; j++) this[pth_arr[i]] = this[pth_arr[i]].replace(RegExp(arr1[j], "gi"), arr2[j]); if (inRev[i]) this[pth_arr[i]] = this[pth_arr[i]].replace(/%BIO_ALBUMARTIST%|%BIO_ARTIST%/gi, "%BIO_ALBUMARTIST%"); if (inBio[i]) this[pth_arr[i]] = this[pth_arr[i]].replace(/%BIO_ARTIST%|%BIO_ALBUMARTIST%/gi, "%BIO_ARTIST%");}
    }
    var alb_top = [], bio_sim = []; this.alb_ix = 0; this.albartFields = []; this.albFields = []; this.albums = []; this.albumsUniq = []; this.art_ix = 0; this.artFields = []; this.artists = []; this.artistsUniq = [];
    var artFields = utils.ReadINI(this.bio_ini, "NAMES", this.def_tf[1].name).replace(RegExp(this.def_tf[1].name, "gi"), ""); for (i = 0; i < 3; i += 2) artFields = artFields.replace(RegExp(this.def_tf[i].name, "gi"), utils.ReadINI(this.bio_ini, "NAMES", this.def_tf[i].name)); if (!artFields.length) artFields = this.def_tf[1].tf; artFields = artFields.replace(/\$.*?\(/gi, "").replace(/(,(|\s+)\d+)/gi,"").replace(/[,\(\)\[\]\%]/gi,"|").split("|"); for (i = 0; i < artFields.length; i++) {artFields[i] = artFields[i].trim(); if (artFields[i].length) {artFieldsArr.push("%" + artFields[i] + "%"); this.artFields.push(artFields[i]);}}
    var albartFields = utils.ReadINI(this.bio_ini, "NAMES", this.def_tf[0].name).replace(RegExp(this.def_tf[0].name, "gi"), ""); for (i = 1; i < 3; i++) albartFields = albartFields.replace(RegExp(this.def_tf[i].name, "gi"), utils.ReadINI(this.bio_ini, "NAMES", this.def_tf[i].name)); if (!albartFields.length) albartFields = this.def_tf[1].tf; albartFields = albartFields.replace(/\$.*?\(/gi, "").replace(/(,(|\s+)\d+)/gi,"").replace(/[,\(\)\[\]\%]/gi,"|").split("|"); for (i = 0; i < albartFields.length; i++) {albartFields[i] = albartFields[i].trim(); if (albartFields[i].length) this.albartFields.push(albartFields[i]);}
    var albFields = utils.ReadINI(this.bio_ini, "NAMES", this.def_tf[2].name).replace(RegExp(this.def_tf[2].name, "gi"), ""); for (i = 0; i < 2; i++) albFields = albFields.replace(RegExp(this.def_tf[i].name, "gi"), utils.ReadINI(this.bio_ini, "NAMES", this.def_tf[i].name)); if (!albFields.length) albFields = this.def_tf[1].tf; albFields = albFields.replace(/\$.*?\(/gi, "").replace(/(,(|\s+)\d+)/gi,"").replace(/[,\(\)\[\]\%]/gi,"|").split("|"); for (i = 0; i < albFields.length; i++) {albFields[i] = albFields[i].trim(); if (albFields[i].length) this.albFields.push(albFields[i]);}
    this.multi_new = function() {if (!img) return true; switch (true) {case img.artistart: artist_o = artist; artist = this.eval(artFieldsArr); if (!this.mul_item || !img.artistart) return true; else return artist != artist_o || !this.artists.length || !this.art_ix; break; case !img.artistart: alb_id_o = alb_id; alb_id = !this.eval("[%album%]") ? this.eval("%album artist%%path%") : this.eval("%album artist%%album%"); if (!this.mul_item || img.artistart) return true; else return alb_id != alb_id_o || !this.albums.length || !this.alb_ix; break;}}
    this.artistsSame = function() {if (this.mul_item && this.art_ix && this.artists.length && JSON.stringify(init_artists) === JSON.stringify(this.artists)) return true; return false;}
    this.albumsSame = function() {if (this.mul_item && this.alb_ix && this.albums.length && JSON.stringify(init_albums) === JSON.stringify(this.albums)) return true; return false;}

    this.get_multi = function(p_clear) {
        if (!this.mul_item) return; var a = name.artist(), aa = name.alb_artist(), l = name.album(); if (!a) a = "Artist Unknown"; if (!aa) aa = "Artist Unknown"; if (!l) l = "Album Unknown";  var ix = -1, k = 0, lfmBio = this.cleanPth(this.lfmBioPth) + a.clean() + ".txt", lfmSim = this.cleanPth(this.lfmSimPth) + a.clean() + " And Similar Artists.json", mn = "", nm = "", mult_arr = [], sa = "", ta = ""; init_albums = this.albums.slice(0); this.albums = []; init_artists = this.artists.slice(0); this.artists = []; this.artists.push({name: a, field: "", type: "Artist"});
        if (this.file(lfmSim)) { // artists
            var lfm_s = this.json_parse(utils.ReadTextFile(lfmSim)), newStyle = false;
            if (lfm_s) {if (lfm_s[0].hasOwnProperty('name')) {newStyle = true; lfm_s.shift();} var simNo = Math.min(similarNo, lfm_s.length); 
            if (simNo) {this.artists.push({name: "Similar Artists: ", field: "", type: "label"}); for (k = 0; k < simNo; k++) this.artists.push({name: newStyle ? lfm_s[k].name : lfm_s[k], field: "", type: k != simNo - 1 ? "similar" : "similarend"})}}
        } else {
            if (this.file(lfmBio)) {
                var lfm_a = utils.ReadTextFile(lfmBio), kw = "Similar Artists: |Ähnliche Künstler: |Artistas Similares: |Artistes Similaires: |Artisti Simili: |似ているアーティスト: |Podobni Wykonawcy: |Artistas Parecidos: |Похожие исполнители: |Liknande Artister: |Benzer Sanatçılar: |相似艺术家: "
                var sim = lfm_a.match(RegExp(kw)); if (sim) {sim = sim.toString(); ix = lfm_a.lastIndexOf(sim); if (ix != -1) {sa = lfm_a.substring(ix + sim.length); sa = sa.split('\n')[0].trim().split(", ");}}
                if (sa.length < 5) {if (sa) {sa.length = Math.min(similarNo, sa.length); this.artists.push({name: "Similar Artists: ", field: "", type: "label"}); for (k = 0; k < sa.length; k++) this.artists.push({name: sa[k], field: "", type: k != sa.length - 1 ? "similar" : "similarend"});}}
                else {var found = false; for (k = 0; k < bio_sim.length; k++) {if (bio_sim[k].name == a) {sa = bio_sim[k].similar; sa.length = Math.min(similarNo, sa.length); found = true; this.artists.push({name: "Similar Artists: ", field: "", type: "label"}); break;}} if (found) {for (k = 0; k < sa.length; k++) this.artists.push({name: sa[k], field: "", type: k != sa.length - 1 ? "similar" : "similarend"});} else {var getSimilar = new lfm_similar_artists(function() {getSimilar.on_state_change();}, getSimilar_search_done); getSimilar.Search(a, "", "", 4);}}
            }
        }
        for (k = 0; k < artFieldsArr.length; k++) {nm = artFieldsArr[k].replace(/%/g, ""); for (var h = 0; h < this.eval("$meta_num(" + nm + ")"); h++) {mn = "$trim($meta(" + nm + "," + h + "))"; var objName = this.eval(mn); if (!obj_contains(this.artists, objName) && objName.toLowerCase() != this.va) mult_arr.push({name: objName, field: " ~ " + nm.titlecase(), type: "tag"});}}
        if (mult_arr.length > 1) try {json_sort(mult_arr, "name", false); k = mult_arr.length; while (k--) if (k != 0 && mult_arr[k].name.toLowerCase() == mult_arr[k - 1].name.toLowerCase()) {mult_arr[k - 1].field += mult_arr[k].field; mult_arr.splice(k, 1);}} catch(e) {}
        if (mult_arr.length) {this.artists.push({name: "More Tags:", field: "", type: "label"}); this.artists = this.artists.concat(mult_arr); this.artists[this.artists.length - 1].type = "tagend";}
        for (k = 0; k < this.artists.length; k++) this.artists[k].ix = k; this.artistsUniq = this.artists.slice(0); k = this.artistsUniq.length; while (k--) if (this.artistsUniq[k].type == "label") this.artistsUniq.splice(k, 1);
        if (this.file(lfmBio)) { // albums
            var lfm_a = utils.ReadTextFile(lfmBio), kw = "Top Albums: |Top-Alben: |Álbumes Más Escuchados: |Top Albums: |Album Più Ascoltati: |人気アルバム: |Najpopularniejsze Albumy: |Álbuns Principais: |Популярные альбомы: |Toppalbum: |En Sevilen Albümler: |最佳专辑: "; ix = -1;
            var talb = lfm_a.match(RegExp(kw)); if (talb) {talb = talb.toString(); ix = lfm_a.lastIndexOf(talb); if (ix != -1) {ta = lfm_a.substring(ix + talb.length); ta = ta.split('\n')[0].trim().split(", ");}}
            if (ta.length < 7) {if (ta) {this.albums = []; this.albums.push({artist: aa, album: l, type: "Current Album"}); this.albums.push({artist: "Last.fm Top Albums: " + a + ":", album: "Last.fm Top Albums: " + a + ":", type: "label"}); for (k = 0; k < ta.length; k++) this.albums.push({artist: a, album: ta[k], type: k != ta.length - 1 ? "album" : "albumend"});}}
            else {var found = false; for (k = 0; k < alb_top.length; k++) if (alb_top[k].name == a) {ta = alb_top[k].album; found = true; break;} if (found) {this.albums = []; this.albums.push({artist: aa, album: l, type: "Current Album"}); this.albums.push({artist: "Last.fm Top Albums: " + a + ":", album: "Last.fm Top Albums: " + a + ":", type: "label"}); var ln = Math.min(ta.length, 6); for (k = 0; k < ln; k++) this.albums.push({artist: a, album: ta[k], type: k != ta.length - 1 ? "album" : "albumend"});} else {var getTopAlb = new lfm_top_albums(function() {getTopAlb.on_state_change();}, getTopAlb_search_done); getTopAlb.Search(a);}}
        }
        for (k = 0; k < this.albums.length; k++) this.albums[k].ix = k; this.albumsUniq = uniq(this.albums);
        if (!this.artistsSame() && p_clear) this.art_ix = 0; if (!this.albumsSame() && p_clear) this.alb_ix = 0;
    }
    this.getData = function(force, focus, notify, type) {switch (type) {case 0: if (this.server) serv.fetch(force, [this.art_ix, focus, this.artists.slice(0)], [this.alb_ix, focus, this.albums.slice(0)]);else window.NotifyOthers(notify, [[this.art_ix, focus, this.artists.slice(0)], [this.alb_ix, focus, this.albums.slice(0)]]); break; case 1: serv.fetch(force, [this.art_ix, focus, this.artists.slice(0)], [this.alb_ix, focus, this.albums.slice(0)]); break;}}
    var getSimilar_search_done = function(artist, list) {bio_sim.push({name:artist, similar:list}); p.get_multi(true);}
    var getTopAlb_search_done = function(artist, list) {alb_top.push({name:artist, album:list}); p.get_multi(true);}
    var uniq = function(a) {var flags = [], result = []; for (var k = 0; k < a.length; k++) {if (flags[a[k].album.toLowerCase()]) continue; result.push(a[k]); flags[a[k].album.toLowerCase()] = true;} k = result.length; while (k--) if (result[k].type == "label") result.splice(k, 1); return result;}

    this.extra = parseFloat(utils.ReadINI(this.bio_ini, "ADVANCED: CUSTOM COVER PATHS", advCov[0].name)); if (this.extra !== 1 && this.extra !== 0) this.extra = advCov[0].path;
    if (this.extra) {this.extraPaths = []; for (i = 1; i < advCov.length; i++) {var ep = utils.ReadINI(this.bio_ini, "ADVANCED: CUSTOM COVER PATHS", advCov[i].name).replace(/%profile%\\/i, fb.ProfilePath); for (j = 0; j < 3; j++) ep = ep.replace(RegExp(this.def_tf[j].name, "gi"), this[tf_arr[j]]); if (ep) this.extraPaths.push(ep);}}
    var langSetOK = false; this.langArr = ["EN", "DE", "ES", "FR", "IT", "JA", "PL", "PT", "RU", "SV", "TR", "ZH"]; this.lfmLang = utils.ReadINI(this.bio_ini, "LASTFM LANGUAGE", this.lang[0].name).toLowerCase(); this.lfmLang_ix = 0;
    this.getLangIndex = function(n) {if (n) this.lfmLang = n; for (i = 0; i < this.langArr.length; i++) if (this.langArr[i].toLowerCase() == this.lfmLang) {langSetOK = true; return this.lfmLang_ix = i;}}
    this.getLangIndex(); if (!langSetOK) this.lfmLang = "en"; this.updIniLang = function(n) {utils.WriteINI(this.bio_ini, "LASTFM LANGUAGE", this.lang[0].name, n);}

    this.arc = 10; this.im_l = 0; this.im_r = 100; this.im_t = 0; this.im_b = 100; this.tx_l = 0; this.tx_r = 100; this.tx_t = 0; this.tx_b = 100; this.iBoxL = 0; this.iBoxT = 0; this.iBoxH = 100; this.iBoxW = 100; this.tBoxL = 0; this.tBoxT = 0; this.tBoxH = 100; this.tBoxW = 100; this.minH = 50;
    this.newStyle = false; this.sameStyle = window.GetProperty("SYSTEM.Bio & Rev Same Style", true); this.style_arr = []; this.styles = this.json_parse(window.GetProperty("SYSTEM.Freestyle Custom", JSON.stringify([])));
    if (!this.styles || this.styles.constructor !== Array) {window.SetProperty("SYSTEM.Freestyle Custom BackUp", window.GetProperty("SYSTEM.Freestyle Custom")); this.styles = []; window.SetProperty("SYSTEM.Freestyle Custom", JSON.stringify(this.styles)); fb.ShowPopupMessage("Unable to load custom styles.\n\nThe save location was corrupt. Custom styles have been reset.\n\nThe original should be backed up to \"SYSTEM.Freestyle Custom BackUp\" in panel properties.", "Biography");}
    else {var valid = true; for (i = 0; i < this.styles.length; i++) if (!this.styles[i].hasOwnProperty('name') || isNaN(this.styles[i].imL) || isNaN(this.styles[i].imR) || isNaN(this.styles[i].imT) || isNaN(this.styles[i].imB) || isNaN(this.styles[i].txL) || isNaN(this.styles[i].txR) || isNaN(this.styles[i].txT) || isNaN(this.styles[i].txB)) valid = false; if (!valid) {window.SetProperty("SYSTEM.Freestyle Custom BackUp", window.GetProperty("SYSTEM.Freestyle Custom")); this.styles = []; window.SetProperty("SYSTEM.Freestyle Custom", JSON.stringify(this.styles)); fb.ShowPopupMessage("Unable to load custom styles.\n\nThe save location was corrupt. Custom styles have been reset.\n\nThe original should be backed up to \"SYSTEM.Freestyle Custom BackUp\" in panel properties.", "Biography");}}
    this.overlay = this.json_parse(window.GetProperty("SYSTEM.Overlay", JSON.stringify({"name":"Overlay", "imL":0, "imR":0, "imT":0, "imB":0, "txL":0, "txR":0, "txT":0.632, "txB":0})));
    if (!this.overlay || !this.overlay.hasOwnProperty('name') || isNaN(this.overlay.imL) || isNaN(this.overlay.imR) || isNaN(this.overlay.imT) || isNaN(this.overlay.imB) || isNaN(this.overlay.txL) || isNaN(this.overlay.txR) || isNaN(this.overlay.txT) || isNaN(this.overlay.txB)) {window.SetProperty("SYSTEM.Overlay BackUp", window.GetProperty("SYSTEM.Overlay")); this.overlay = {"name":"Overlay", "imL":0, "imR":0, "imT":0, "imB":0, "txL":0, "txR":0, "txT":0.632, "txB":0}; window.SetProperty("SYSTEM.Overlay", JSON.stringify(this.overlay)); fb.ShowPopupMessage("Unable to load \"SYSTEM.Overlay\".\n\nThe save location was corrupt. The overlay style has been reset to default.\n\nThe original should be backed up to \"SYSTEM.Overlay BackUp\" in panel properties.", "Biography");}
    this.styleArr = function() {this.style_arr = ["Top", "Right", "Bottom", "Left", "Overlay"]; for (var k = 0; k < this.styles.length; k++) this.style_arr.push(this.styles[k].name);}; this.styleArr();

    this.sizes = function (bypass) {
        if (window.GetProperty("SYSTEM.Bottom Size Correction", false)) {this.w = this.img_only ? window.Width : window.Width - window.Width * 18 / 1018; this.h = this.img_only ? window.Height : window.Height - window.Height * 18 / 1018;} // size correction can be set to true for optimal text positioning where panel size is increased to compensate for shadow effect
        this.sbar_o = [2 + ui.arrow_pad, Math.max(Math.floor(ui.scr_but_w * 0.2), 3) + ui.arrow_pad * 2, 0][ui.scr_type], top_corr = [this.sbar_o - (ui.but_h - ui.scr_but_w) / 2, this.sbar_o, 0][ui.scr_type], bot_corr = [(ui.but_h - ui.scr_but_w) / 2 - this.sbar_o, -this.sbar_o, 0][ui.scr_type];
        if (!this.sameStyle && img) this.style = img.artistart ? this.bioStyle : this.revStyle;
        switch (true){
            case this.img_only: // img_only
                this.img_l = this.bor_l; this.img_r = this.bor_r; this.img_t = this.bor_t; this.img_b = this.bor_b;
                this.imgs = Math.max(Math.min(this.h - this.bor_t - this.bor_b, this.w - this.bor_l - this.bor_r), 10);
                break;
            case this.text_only: // text_only
                this.lines_drawn = Math.max(Math.floor((this.h - text_t - text_b - ui.heading_h) / ui.font_h), 0);
                this.text_l = text_l;
                this.text_r = ui.scrollbar_show ? Math.max(text_r, ui.sbar_sp + 10) : text_r;
                this.text_t = !topAlign ? text_t + (this.h - text_t - text_b - this.lines_drawn * ui.font_h + ui.heading_h) / 2 : text_t + ui.heading_h;
                this.text_w = this.w - this.text_l - this.text_r;
                if (ui.scrollbar_show) {this.sbar_x = this.w - ui.sbar_sp; this.sbar_y = (ui.scr_type < js_stnd ? this.text_t : 0) + top_corr; this.sbar_h = (ui.scr_type < js_stnd ? ui.font_h * this.lines_drawn + bot_corr : this.h - this.sbar_y) + bot_corr;}
                this.rp_x = 0; this.rp_y = 0; this.rp_w = this.w; this.rp_h = this.h;
                break;
            case this.style == 0: // top
                this.img_l = this.bor_l; this.img_r = this.bor_r; this.img_t = this.bor_t; this.img_b = this.bor_b;
                txt_h = Math.round((this.h - this.img_t - text_b) * (1 - this.rel_imgs));
                this.lines_drawn = Math.max(Math.floor((txt_h - ui.heading_h) / ui.font_h), 0);
                txt_h = this.lines_drawn * ui.font_h + ui.gap;
                this.imgs = Math.max(this.h - txt_h - this.img_t  - text_b - ui.heading_h, 10);
                this.text_l = text_l;
                this.text_r = ui.scrollbar_show ? Math.max(text_r, ui.sbar_sp + 10) : text_r;
                this.text_t = this.img_t + this.imgs + ui.gap + ui.heading_h;
                this.text_w = this.w - this.text_l - this.text_r;
                this.text_h = txt_h + ui.heading_h;
                if (ui.scrollbar_show) {this.sbar_x = this.w - ui.sbar_sp; this.sbar_y = (ui.scr_type < js_stnd || ui.heading ? this.text_t : this.img_t + this.imgs) + top_corr; this.sbar_h = (ui.scr_type < js_stnd ? ui.font_h * this.lines_drawn + bot_corr : this.h - this.sbar_y) + bot_corr;}
                this.rp_x = 0; this.rp_y = this.img_t + this.imgs; this.rp_w = this.w; this.rp_h = this.h - this.rp_y;
                break;
            case this.style == 1: // right
                this.img_l = this.bor_l; this.img_r = this.bor_r; this.img_t = this.bor_t; this.img_b = this.bor_b;
                var txt_sp = Math.round((this.w - text_l - this.img_r) * (1 - this.rel_imgs)); txt_h = this.h - text_t - text_b;
                this.lines_drawn = Math.max(Math.floor((txt_h - ui.heading_h) / ui.font_h), 0);
                this.imgs = Math.max(this.w - txt_sp -  this.img_r - text_l - ui.gap, 10);
                if (ui.scrollbar_show) txt_sp -= (ui.sbar_sp + 10);
                this.text_l = text_l;
                this.text_r = ui.scrollbar_show ? Math.max(text_r, ui.sbar_sp + 10) : text_r;
                this.text_t = !topAlign ? text_t + (this.h - text_t - text_b - this.lines_drawn * ui.font_h + ui.heading_h) / 2 : text_t + ui.heading_h;
                this.text_w = txt_sp;
                this.text_h = this.lines_drawn * ui.font_h + ui.heading_h;
                this.img_l = text_l + txt_sp + ui.gap + (ui.scrollbar_show ? ui.sbar_sp + 10 : 0);
                if (ui.scrollbar_show) {this.sbar_x = this.text_l + this.text_w + 10; this.sbar_x = this.sbar_x - (ui.scr_w - ui.scr_but_w < 5 || ui.scr_type == 3 ? 1 : 0); this.sbar_y = (ui.scr_type < js_stnd || ui.heading ? this.text_t : 0) + top_corr; this.sbar_h = ui.scr_type < js_stnd ? ui.font_h * this.lines_drawn + bot_corr * 2 : this.h - this.sbar_y  + bot_corr;}
                this.rp_x = 0; this.rp_y = 0; this.rp_w = this.img_l; this.rp_h = this.h;
                break;
            case this.style == 2: // bottom
                this.img_l = this.bor_l; this.img_r = this.bor_r; this.img_t = this.bor_t; this.img_b = this.bor_b;
                txt_h = Math.round((this.h - text_t - this.img_b) * (1 - this.rel_imgs));
                this.lines_drawn = Math.max(Math.floor((txt_h - ui.heading_h) / ui.font_h), 0);
                txt_h = this.lines_drawn * ui.font_h + ui.gap;
                this.imgs = Math.max(this.h - txt_h - this.img_b  - text_t - ui.heading_h, 10);
                this.img_t = this.h - this.bor_b - this.imgs;
                this.text_l = text_l;
                this.text_r = ui.scrollbar_show ? Math.max(text_r, ui.sbar_sp + 10) : text_r;
                this.text_t = this.img_t - txt_h;
                this.text_w = this.w - this.text_l - this.text_r;
                this.text_h = txt_h - ui.gap + ui.heading_h;
                if (ui.scrollbar_show) {this.sbar_x = this.w - ui.sbar_sp; this.sbar_y = (ui.scr_type < js_stnd || ui.heading ? this.text_t : 0) + top_corr; this.sbar_h = ui.scr_type < js_stnd ? ui.font_h * this.lines_drawn + bot_corr * 2 : this.img_t - this.sbar_y + bot_corr;}
                this.rp_x = 0; this.rp_y = 0; this.rp_w = this.w; this.rp_h = this.img_t;
                break;
            case this.style == 3: // left
                this.img_l = this.bor_l; this.img_r = this.bor_r; this.img_t = this.bor_t; this.img_b = this.bor_b;
                this.text_r = ui.scrollbar_show ? Math.max(text_r, ui.sbar_sp + 10) : text_r;
                var txt_sp = Math.round((this.w - this.img_l - this.text_r) * (1 - this.rel_imgs)); 
                this.text_h = this.h - text_t - text_b;
                this.lines_drawn = Math.max(Math.floor((this.text_h - ui.heading_h) / ui.font_h), 0);
                this.imgs = Math.max(this.w - txt_sp -  this.img_l -  this.text_r - ui.gap, 10);
                this.text_l = this.img_l + this.imgs + ui.gap;
                this.text_t = !topAlign ? text_t + (this.h - text_t - text_b - this.lines_drawn * ui.font_h + ui.heading_h) / 2 : text_t + ui.heading_h;
                this.text_w = txt_sp;
                if (ui.scrollbar_show) {this.sbar_x = this.w - ui.sbar_sp; this.sbar_y = (ui.scr_type < js_stnd || ui.heading ? this.text_t : 0) + top_corr; this.sbar_h = ui.scr_type < js_stnd ? ui.font_h * this.lines_drawn + bot_corr * 2 : this.h - this.sbar_y  + bot_corr;}
                this.rp_x = this.text_l; this.rp_y = 0; this.rp_w = this.w - this.rp_x; this.rp_h = this.h;
                break;
            case this.style > 3:
                try {if (this.style - 5 >= this.styles.length) this.get_style_fallback();
                var obj = this.style == 4 ? this.overlay : this.styles[this.style - 5];
                if (!bypass) {this.im_l = Math.min(Math.max(obj.imL, 0), 1); this.im_r = Math.min(Math.max(obj.imR, 0), 1); this.im_t = Math.min(Math.max(obj.imT, 0), 1); this.im_b = Math.min(Math.max(obj.imB, 0), 1); this.tx_l = Math.min(Math.max(obj.txL, 0), 1); this.tx_r = Math.min(Math.max(obj.txR, 0), 1); this.tx_t = Math.min(Math.max(obj.txT, 0), 1); this.tx_b = Math.min(Math.max(obj.txB, 0), 1);}
                } catch (e) {this.get_style_fallback(); obj = this.overlay; this.im_l = Math.min(Math.max(obj.imL, 0), 1); this.im_r = Math.min(Math.max(obj.imR, 0), 1); this.im_t = Math.min(Math.max(obj.imT, 0), 1); this.im_b = Math.min(Math.max(obj.imB, 0), 1); this.tx_l = Math.min(Math.max(obj.txL, 0), 1); this.tx_r = Math.min(Math.max(obj.txR, 0), 1); this.tx_t = Math.min(Math.max(obj.txT, 0), 1); this.tx_b = Math.min(Math.max(obj.txB, 0), 1);}
                var imL = Math.round(this.im_l * this.w), imR = Math.round(this.im_r * this.w), imT = Math.round(this.im_t * this.h), imB = Math.round(this.im_b * this.h), txL = Math.round(this.tx_l * this.w), txR = Math.round(this.tx_r * this.w), txT = Math.round(this.tx_t * this.h), txB = Math.round(this.tx_b * this.h);
                this.iBoxL = Math.max(imL, 0); this.iBoxT = Math.max(imT, 0); this.iBoxW = this.w - imL - imR; this.iBoxH = this.h - imT - imB;
                this.img_l = imL + this.bor_l; this.img_r = imR + this.bor_r; this.img_t = imT + this.bor_t; this.img_b = imB + this.bor_b;
                txt_h = Math.round((this.h - txT - txB - t_t - t_b));
                this.lines_drawn = Math.max(Math.floor((txt_h - ui.heading_h) / ui.font_h), 0);
                this.text_l = txL + t_l;
                this.text_r = txR + (ui.scrollbar_show ? Math.max(t_r, ui.sbar_sp + 10) : t_r);
                this.text_t = txT + ui.heading_h + t_t;
                this.text_w = this.w - this.text_l - this.text_r;
                this.text_h = Math.max(this.lines_drawn * ui.font_h + ui.heading_h, ui.font_h + ui.heading_h)
                this.tBoxL = Math.max(txL, 0); this.tBoxT = Math.max(txT, 0); this.tBoxW = this.w - Math.max(txL, 0) - Math.max(txR, 0); this.tBoxH = this.h - Math.max(txT, 0) - Math.max(txB, 0); this.minH = ui.font_h + ui.heading_h + t_t + t_b;
                if (ui.overlayStyle == 2) this.arc_w = Math.max(Math.min(this.arc_w, this.tBoxW / 3, this.tBoxH / 3), 1);
                if (ui.overlayStyle) this.arc = Math.max(ui.font_h / 1.5, 1);
                this.imgs = this.iBoxT + 100 < this.tBoxT && this.tBoxT < this.iBoxT + this.iBoxH && (this.tBoxL < this.iBoxL + this.iBoxW || this.tBoxL + this.tBoxW < this.iBoxL + this.iBoxW) ? this.tBoxT - this.iBoxT : Math.min(this.h - imT - imB - this.bor_t - this.bor_b, this.w - imL - imR - this.bor_l - this.bor_r);
                if (ui.scrollbar_show) {this.sbar_x = this.tBoxL + this.tBoxW - ui.sbar_sp - ui.arc_w; this.sbar_y = this.text_t + top_corr; this.sbar_h = ui.font_h * this.lines_drawn + bot_corr * 2;}
                this.rp_x = this.tBoxL; this.rp_y = this.tBoxT; this.rp_w = this.tBoxW; this.rp_h = this.tBoxH;
                break;
        } if (ui.scr_type == 2) {this.sbar_y += 1; this.sbar_h -= 2;} this.text_w = Math.max(this.text_w, 10);
    }

    this.mode = function(n) {
        switch (n) {
            case 1: this.img_only = false; window.SetProperty("SYSTEM.Image Only", this.img_only); if (this.text_only) var text_only = true; this.text_only = false; window.SetProperty("SYSTEM.Text Only", this.text_only); this.sizes(); img.clear_rs_cache(); if (!this.art_ix && img.artistart && !t.mulArtist || !this.alb_ix && !img.artistart && !t.mulAlbum) {t.album_reset(); t.artist_reset(); t.grab_text(!text_only ? false : true); img.get_images();} else {t.get_multi(true, this.art_ix, this.alb_ix); img.get_multi(this.art_ix);} break;
            case 2: this.img_only = true; window.SetProperty("SYSTEM.Image Only", this.img_only); this.text_only = false; window.SetProperty("SYSTEM.Text Only", this.text_only); img.setCrop(); this.sizes(); img.clear_rs_cache(); img.get_images(); break;
            case 3: this.text_only = true; window.SetProperty("SYSTEM.Text Only", this.text_only); this.img_only = false; window.SetProperty("SYSTEM.Image Only", this.img_only); this.sizes(); if (ui.blur) img.clear_rs_cache(); if (!this.art_ix && img.artistart && !t.mulArtist || !this.alb_ix && !img.artistart && !t.mulAlbum) {t.album_reset(); t.artist_reset(); t.grab_text(true); if (ui.blur) img.get_images();} else {t.get_multi(true, this.art_ix, this.alb_ix); if (ui.blur) img.get_multi(this.art_ix); img.set_chk_arr(null);} break;
        }
    }

    this.createStyle = function() {
        var ns = InputBox("Enter new style name\n\n\Proceed?\n\nFreestyle layouts offer drag style positioning of image & text boxes + text overlay\n\nPress CTRL to alter layouts", "Create New Freestyle Layout", "My Style"); if (!ns) return false; else {
        switch (this.style) {
            case 0: var txt_h = Math.round((this.h - this.bor_t - text_b) * (1 - this.rel_imgs)), lines_drawn = Math.max(Math.floor((txt_h - ui.heading_h) / ui.font_h), 0); txt_h = lines_drawn * ui.font_h + ui.gap; var imgs = Math.max(this.h - txt_h - this.bor_t  - text_b - ui.heading_h, 10); this.im_b = (this.h - this.bor_t - imgs - this.bor_b) / this.h; this.tx_t = (this.bor_t + imgs - text_t + ui.gap) / this.h; this.im_l = 0; this.im_r = 0; this.im_t = 0; this.tx_l = 0; this.tx_r = 0; this.tx_b = 0; break;
            case 1: var txt_sp = Math.round((this.w - text_l - this.bor_r) * (1 - this.rel_imgs)), lines_drawn = Math.max(Math.floor((this.h - text_t - text_b - ui.heading_h) / ui.font_h), 0), te_t = !topAlign ? text_t + (this.h - text_t - text_b - lines_drawn * ui.font_h + ui.heading_h) / 2 : text_t + ui.heading_h; this.im_l = (txt_sp + ui.gap + (ui.scrollbar_show ? ui.sbar_sp + 10 : 0)) / this.w; this.tx_r = (this.w - (txt_sp + text_r)) / this.w; this.tx_t = (te_t - ui.heading_h - text_t) / this.h; this.im_r = 0; this.im_t = 0; this.im_b = 0; this.tx_l = 0; this.tx_b = 0; break;
            case 2: var txt_h = Math.round((this.h - text_t - this.bor_b) * (1 - this.rel_imgs)), lines_drawn = Math.max(Math.floor((txt_h - ui.heading_h) / ui.font_h), 0); txt_h = lines_drawn * ui.font_h + ui.gap; var imgs = Math.max(this.h - txt_h - this.bor_b  - text_t - ui.heading_h, 10), img_t = this.h - this.bor_b - imgs; this.im_t = img_t / this.h; this.tx_b = (this.h - img_t - text_b + ui.gap) / this.h; this.im_l = 0; this.im_r = 0; this.im_b = 0; this.tx_l = 0; this.tx_r = 0; this.tx_t = 0; break;
            case 3: var te_r = ui.scrollbar_show ? Math.max(text_r, ui.sbar_sp + 10) : text_r, txt_sp = Math.round((this.w - this.bor_l - te_r) * (1 - this.rel_imgs)), imgs = Math.max(this.w - txt_sp -  this.bor_l -  te_r - ui.gap, 10), lines_drawn = Math.max(Math.floor((this.h - text_t - text_b - ui.heading_h) / ui.font_h), 0), te_t = !topAlign ? text_t + (this.h - text_t - text_b - lines_drawn * ui.font_h + ui.heading_h) / 2 : text_t + ui.heading_h; this.im_r = (this.w - this.bor_l - imgs - this.bor_r) / this.w; this.tx_l = (this.bor_l + imgs - text_l + ui.gap) / this.w; this.tx_t = (te_t - ui.heading_h - text_t) / this.h; this.im_l = 0; this.im_t = 0; this.im_b = 0; this.tx_r = 0; this.tx_b = 0; break;
        }
        for (var k = 0; k < this.styles.length; k++) if (this.styles[k].name == ns) ns = ns + " New";
        this.styles.push({"name":ns, "imL":this.im_l, "imR":this.im_r, "imT":this.im_t, "imB":this.im_b, "txL":this.tx_l, "txR":this.tx_r, "txT":this.tx_t, "txB":this.tx_b})
        json_sort(this.styles, "name", false); window.SetProperty("SYSTEM.Freestyle Custom", JSON.stringify(this.styles));
        for (k = 0; k < this.styles.length; k++) if (this.styles[k].name == ns) {if (this.sameStyle) this.style = k + 5; else if (img.artistart) this.bioStyle = k + 5; else this.revStyle = k + 5; break;}
        this.styleArr(); t.toggle(8); timer.reset(timer.source, timer.sourcei); timer.source = window.SetTimeout(function() {p.newStyle = false; window.Repaint(); timer.source = false;}, 10000); if (timer.source !== 0) {this.newStyle = true; window.Repaint();}}
    }
    this.deleteStyle = function(n) {var ns = InputBox("Delete style: " + this.style_arr[n] + "\n\nProceed?\n\nLayout will be set to top style", "Delete Current Style", "Action: Delete Style"); if (!ns) return false; else {this.styles.splice(n - 5, 1); window.SetProperty("SYSTEM.Freestyle Custom", JSON.stringify(this.styles)); this.style = 0; if (!this.sameStyle) {if (img) {if (img.artistart) this.bioStyle = 0; else this.revStyle = 0;}} this.styleArr(); t.toggle(8);}}
    this.exportStyle = function(n) {var ns = InputBox("Export style: " + this.style_arr[n] + "\n\n\Proceed?", "Export Current Style To Other Biography Panels", "Action: Export Style"); if (!ns) return false; else window.NotifyOthers("custom_style_jb", JSON.stringify(this.styles[n - 5]));}
    this.get_style_fallback = function() {this.style = 4; if (!this.sameStyle) {if (img) {if (img.artistart) this.bioStyle = 4; else this.revStyle = 4;} else {this.bioStyle = 4; this.revStyle = 4;}} window.SetProperty("SYSTEM.Layout", this.style); window.SetProperty("SYSTEM.Layout Bio", this.bioStyle); window.SetProperty("SYSTEM.Layout Rev", this.revStyle); fb.ShowPopupMessage("Unable to locate style. Using overlay layout instead.", "Biography");}
    this.on_notify = function(info) {try {var rec = this.json_parse(info); for (var k = 0; k < this.styles.length; k++) if (this.styles[k].name == rec.name) rec.name = rec.name + " New"; this.styles.push(rec); json_sort(this.styles, "name", false); window.SetProperty("SYSTEM.Freestyle Custom", JSON.stringify(this.styles)); this.styleArr();} catch (e) {}}
    this.renameStyle = function(n) {var ns = InputBox("Rename style: " + this.style_arr[n] + "\n\nEnter new name\n\n\Proceed?", "Rename Current Style", this.style_arr[n]); if (!ns || ns == this.style_arr[n]) return false; else {for (var k = 0; k < this.styles.length; k++) if (this.styles[k].name == ns) ns = ns + " New"; this.styles[n - 5].name = ns; json_sort(this.styles, "name", false); window.SetProperty("SYSTEM.Freestyle Custom", JSON.stringify(this.styles)); for (k = 0; k < this.styles.length; k++) if (this.styles[k].name == ns) {this.style = k + 5; break;} this.styleArr(); window.Repaint();}}
    this.resetStyle = function(n) {var ns = InputBox((this.style < 4 ? "Reset Image Size to Default:\n\nStyle: " : "Reset layout to default:\n\nStyle: ") + this.style_arr[n] + "\n\n\Proceed?", "Reset Current Style", "Action: Reset Style"); if (!ns) return false; else {if (this.style < 4) {this.rel_imgs = 0.7; window.SetProperty("SYSTEM.Layout Image Size 0-1", this.rel_imgs);} else {var obj = this.style == 4 ? this.overlay : this.styles[this.style - 5]; obj.name = this.style_arr[n]; obj.imL = 0; obj.imR = 0; obj.imT = 0; obj.imB = 0; obj.txL = 0; obj.txR = 0; obj.txT = 0.632; obj.txB = 0; window.SetProperty(this.style == 4 ? "SYSTEM.Overlay" : "SYSTEM.Freestyle Custom", JSON.stringify(this.style == 4 ? this.overlay : this.styles));} t.toggle(14);}}
}
var p = new panel_operations();

function lfm_similar_artists(state_callback, on_search_done_callback) {
    var artist, done, fn_sim, list = [], handles, lmt, pth_sim, retry = false; this.xmlhttp = null; this.func = null; this.ready_callback = state_callback; this.on_search_done_callback = on_search_done_callback;
	this.on_state_change = function() {if (this.xmlhttp != null && this.func != null) if (this.xmlhttp.readyState == 4) {if (this.xmlhttp.status == 200) this.func(); else if (this.on_search_done_callback) this.on_search_done_callback(artist, list, done, handles);}}

    this.Search = function(p_artist, p_done, p_handles, p_lmt, p_pth_sim, p_fn_sim) {
        artist = p_artist; done = p_done; handles = p_handles; lmt = p_lmt; pth_sim = p_pth_sim; fn_sim = p_fn_sim; if (retry) lmt = lmt == 249 ? 240 : lmt + 10; this.func = null; this.xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
        var URL = "http://ws.audioscrobbler.com/2.0/?format=json" + p.lfm + "&method=artist.getSimilar&artist=" + encodeURIComponent(artist) + "&limit=" + lmt + "&autocorrect=1";
        this.func = this.Analyse; this.xmlhttp.open("GET", URL); this.xmlhttp.onreadystatechange = this.ready_callback; this.xmlhttp.setRequestHeader('User-Agent', "foobar2000_script"); this.xmlhttp.send();
    }
    
    this.Analyse = function() {
        var data = p.json_parse(this.xmlhttp.responsetext, "similarartists.artist", "name\":");
        if ((!data || data.length < lmt) && !retry) {retry = true; return this.Search(artist, done, handles, lmt, pth_sim, fn_sim);}
        switch (true) {
            case lmt < 15: if (data) {var ln = Math.min(data.length, 4); for (var i = 0; i < ln; i++) list[i] = data[i].name; this.on_search_done_callback(artist, list, done, handles);} break;
            case lmt > 99: if (data) {for (var i = 0; i < data.length; i++) list[i] = {name:data[i].name, score:Math.round(data[i].match * 100)}; list.unshift({name:artist, score:100}); p.buildFullPth(pth_sim); p.save(fn_sim, JSON.stringify(list)); if (p.lfm_sim) {p.get_multi(false); window.NotifyOthers("get_multi_jb", "get_multi_jb");}} break;
        }
    }
}

function lfm_top_albums(state_callback, on_search_done_callback) {
    var artist, popAlbums = [], topAlbums = []; this.xmlhttp = null; this.func = null; this.ready_callback = state_callback; this.on_search_done_callback = on_search_done_callback;
    this.on_state_change = function() {if (this.xmlhttp != null && this.func != null) if (this.xmlhttp.readyState == 4) {if (this.xmlhttp.status == 200) this.func(); else {this.on_search_done_callback(artist, list);}}}

    this.Search = function(p_artist) {
        artist = p_artist; this.func = null; this.xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
        var URL = "https://www.last.fm/music/" + encodeURIComponent(artist) + "/+albums";
        this.func = this.Analyse; this.xmlhttp.open("GET", URL); this.xmlhttp.onreadystatechange = this.ready_callback; this.xmlhttp.send();
    }
	
	this.Analyse = function() {
		var doc = new ActiveXObject("htmlfile"), i = 0; doc.open(); var div = doc.createElement('div'); div.innerHTML = this.xmlhttp.responseText;
		ui.htmlParse(div.getElementsByTagName('h3'), 'className', 'resource-list--release-list-item-name', function(v) {i < 4 ? popAlbums.push(v.innerText.trim().titlecase()) : topAlbums.push(v.innerText.trim().titlecase()); i++; if (i == 10) return true;});
		doc.close();
		if (popAlbums.length) {
			var mapAlbums = [];
			for (i = 0; i < topAlbums.length; i++) mapAlbums.push(topAlbums[i].cut());
			var match = false;
			for (i = 0; i < mapAlbums.length; i++) if (mapAlbums[i].indexOf(popAlbums[0].cut()) == 0) {match = true; break;}
			if (topAlbums.length > 5 && !match) topAlbums.splice(5, 0, popAlbums[0]); else topAlbums = topAlbums.concat(popAlbums);
		}
		topAlbums.length = Math.min(6, topAlbums.length);
		this.on_search_done_callback(artist, topAlbums);
	}
}

function names() {
    this.alb_strip = parseFloat(utils.ReadINI(p.bio_ini, "MISCELLANEOUS", p.def_tf[3].name)); if (this.alb_strip !== 1 && this.alb_strip !== 0) this.alb_strip = p.def_tf[3].tf;    
    this.alb_artist = function(focus) {return p.eval("[$trim(" + p.aa_tf + ")]", focus);}
    this.artist = function(focus) {return p.eval("[$trim(" + p.a_tf + ")]", focus);}
    this.albm = function(focus) {return p.eval("[" + p.l_tf + "]", focus).replace(/CD(\s*\d|\.0\d)|CD\s*(One|Two|Three)|Disc\s*\d|Disc\s*(III|II|I|One|Two|Three)\b/gi,"").replace(/\(\s*\)|\[\s*\]/g, " ").replace(/\s\s+/g, " ").replace(/-\s*$/g, " ").trim();}
    this.album = function(focus) {if (!this.alb_strip) return this.albm(focus); return p.eval("[" + p.l_tf + "]", focus).replace(/CD(\s*\d|\.0\d)|CD\s*(One|Two|Three)|Disc\s*\d|Disc\s*(III|II|I|One|Two|Three)\b|(Bonus\s*Track|Collector's|(Digital\s*|Super\s*|)Deluxe|Digital|Expanded|Limited|Platinum|Reissue|Special)\s*(Edition|Version)|(Bonus\s*(CD|Disc))|\d\d\w\w\s*Anniversary\s*(Expanded\s*|Re(-|)master\s*|)(Edition|Re(-|)master|Version)|((19|20)\d\d(\s*|\s*-\s*)|)(Digital(ly|)\s*|)(Re(-|)master(ed|)|Re(-|)recorded)(\s*Edition|\s*Version|)|\(Deluxe\)|\(Mono\)|\(Reissue\)|\(Revisited\)|\(Stereo\)|\(Web\)|\[Deluxe\]|\[Mono\]|\[Reissue\]|\[Revisited\]|\[Stereo\]|\[Web\]/gi,"").replace(/\(\s*\)|\[\s*\]/g, " ").replace(/\s\s+/g, " ").replace(/-\s*$/g, " ").trim();}
}
var name = new names();

function scrollbar() {
    smoothness = 1 - window.GetProperty("ADV.Scroll: Smooth Scroll Level 0-1", 0.6561); smoothness = Math.max(Math.min(smoothness, 0.99), 0.01); this.count = -1; this.draw_timer = false; this.hover = false; this.s1 = 0; this.s2 = 0; this.scroll_step = window.GetProperty(" Scroll - Mouse Wheel: Page Scroll", false); this.smooth = window.GetProperty(" Scroll: Smooth Scroll", true); this.timer_but = false;
    this.x = 0; this.y = 0; this.w = 0; this.h = 0; this.bar_ht = 0; this.but_h = 0; this.bar_y = 0; this.row_count = 0; this.scroll = 0; this.delta = 0; this.ratio = 1; this.rows_drawn = 0; this.row_h = 0; this.scrollbar_height = 0; this.scrollable_lines = 0; this.scrollbar_travel = 0;
    this.b_is_dragging = false; this.drag_distance_per_row; this.initial_drag_y = 0; // dragging
    this.leave = function() {if (this.b_is_dragging) return; this.hover = false; this.hover_o = false; window.RepaintRect(this.x, this.y, this.w, this.h);}
    this.nearest = function(y) {y = (y - this.but_h) / this.scrollbar_height * this.scrollable_lines * this.row_h; y = y / this.row_h; y = Math.round(y) * this.row_h; return y;}
    this.reset = function() {this.delta = this.scroll = this.s1 = this.s2 = 0; this.metrics(this.x, this.y, this.w, this.h, this.rows_drawn, this.row_h);}
    this.scroll_timer = function() {var that = this; this.draw_timer = window.SetInterval(function() {if (p.w < 1 || !window.IsVisible) return; that.smooth_scroll();}, 16);}
    this.set_rows = function(row_count) {this.row_count = row_count; this.metrics(this.x, this.y, this.w, this.h, this.rows_drawn, this.row_h);}
    this.set_scroll = function(new_scroll) {var s = Math.max(0, Math.min(new_scroll, this.scrollable_lines * this.row_h)); if (s == this.scroll) return; this.scroll = s; this.delta = this.scroll; this.bar_y = this.but_h + this.scrollbar_travel * (this.delta * this.ratio) / (this.row_count * this.row_h); p.paint();}
    this.wheel = function(step, pgkey) {this.check_scroll(this.scroll + step * - (this.scroll_step || pgkey ? this.rows_drawn : 3) * this.row_h);}

    this.metrics = function(x, y, w, h, rows_drawn, row_h) {
        this.x = x; this.y = Math.round(y); this.w = w; this.h = h; this.rows_drawn = rows_drawn; this.row_h = row_h; this.but_h = ui.but_h;
        // draw info
        this.scrollbar_height = Math.round(this.h - this.but_h * 2);
        this.bar_ht = Math.max(Math.round(this.scrollbar_height * this.rows_drawn / this.row_count), 12);
        this.scrollbar_travel = this.scrollbar_height - this.bar_ht;
        // scrolling info
		this.scrollable_lines = this.rows_drawn > 0 ? this.row_count - this.rows_drawn : 0;
        this.ratio = this.row_count / this.scrollable_lines;
        this.bar_y = this.but_h + this.scrollbar_travel * (this.delta * this.ratio) / (this.row_count * this.row_h);
        this.drag_distance_per_row = this.scrollbar_travel / this.scrollable_lines;
    }

    this.lbtn_up = function(p_x, p_y) {
        var x = p_x - this.x; var y = p_y - this.y;
        if (this.b_is_dragging) this.b_is_dragging = false; window.RepaintRect(this.x, this.y, this.w, this.h); this.initial_drag_y = 0;
        if(this.timer_but) {window.ClearTimeout(this.timer_but); this.timer_but = false;}; this.count = -1;
    }

    this.draw = function(gr) {if (this.scrollable_lines > 0) {try {
        switch (ui.scr_type) {
            case 0:
                switch (ui.scr_col) {
                    case 0: gr.FillSolidRect(this.x, this.y + this.bar_y, this.w, this.bar_ht, RGBA(ui.ct, ui.ct, ui.ct, !this.hover && !this.b_is_dragging ? 75 : this.hover && !this.b_is_dragging ? 128 : 192)); break;
                    case 1: gr.FillSolidRect(this.x, this.y + this.bar_y, this.w, this.bar_ht, ui.textcol & (!this.hover && !this.b_is_dragging ? 0x44ffffff : this.hover && !this.b_is_dragging ? 0x77ffffff : 0x99ffffff)); break;
                } break;
            case 1:
                switch (ui.scr_col) {
                    case 0: gr.FillSolidRect(this.x, this.y - p.sbar_o, this.w, this.h + p.sbar_o * 2, RGBA(ui.ct, ui.ct, ui.ct, 15)); gr.FillSolidRect(this.x, this.y + this.bar_y, this.w, this.bar_ht, RGBA(ui.ct, ui.ct, ui.ct, !this.hover && !this.b_is_dragging ? 75 : this.hover && !this.b_is_dragging ? 128 : 192)); break;
                    case 1: gr.FillSolidRect(this.x, this.y - p.sbar_o, this.w, this.h + p.sbar_o * 2, ui.textcol & 0x15ffffff); gr.FillSolidRect(this.x, this.y + this.bar_y, this.w, this.bar_ht, ui.textcol & (!this.hover && !this.b_is_dragging ? 0x33ffffff : this.hover && !this.b_is_dragging ? 0x55ffffff : 0x99ffffff)); break;
                } break;
            case 2: ui.theme.SetPartAndStateId(6, 1); ui.theme.DrawThemeBackground(gr, this.x, this.y, this.w, this.h); ui.theme.SetPartAndStateId(3, !this.hover && !this.b_is_dragging ? 1 : this.hover && !this.b_is_dragging ? 2 : 3); ui.theme.DrawThemeBackground(gr, this.x, this.y + this.bar_y, this.w, this.bar_ht); break;
        }} catch (e) {}}
    }

    this.lbtn_dn = function(p_x, p_y) {
        var x = p_x - this.x; var y = p_y - this.y;
        if (x < 0 || x > this.w || y < 0 || y > this.h || this.row_count <= this.rows_drawn) return;
        if (y < this.but_h || y > this.h - this.but_h) return;
        if (y < this.bar_y) var dir = 1; // above bar
        else if (y > this.bar_y + this.bar_ht) var dir = -1; // below bar
        if (y < this.bar_y || y > this.bar_y + this.bar_ht)
            this.check_scroll(this.nearest(y));
        else { // on bar
            this.b_is_dragging = true; window.RepaintRect(this.x, this.y, this.w, this.h);
            this.initial_drag_y = y - this.bar_y;
        }
    }

    this.move = function(p_x, p_y) {
        var x = p_x - this.x; var y = p_y - this.y;
        if (x < 0 || x > this.w || y > this.bar_y + this.bar_ht || y < this.bar_y) this.hover = false; else this.hover = true;
        if (this.hover != this.hover_o) window.RepaintRect(this.x, this.y, this.w, this.h); this.hover_o = this.hover;
        if (!this.b_is_dragging || this.row_count <= this.rows_drawn) return;
        this.check_scroll(Math.round((y - this.initial_drag_y - this.but_h) / this.drag_distance_per_row) * this.row_h);
    }

    this.check_scroll = function(new_scroll) {
        var s = Math.max(0, Math.min(new_scroll, this.scrollable_lines * this.row_h));
        if (s == this.scroll) return; this.scroll = s;
        if (this.smooth) {if (!this.draw_timer) this.scroll_timer();}
        if (!this.smooth) {this.delta = this.scroll; this.bar_y = this.but_h + this.scrollbar_travel * (this.delta * this.ratio) / (this.row_count * this.row_h); p.paint();}
    }

    this.smooth_scroll = function() {
        if (this.delta <= 0.5) {this.delta = 0; this.bar_y = this.but_h + this.scrollbar_travel * (this.delta * this.ratio) / (this.row_count * this.row_h); p.paint();}
         if(Math.abs(this.scroll - this.delta) > 0.5) {
            this.s1 += (this.scroll - this.s1) * smoothness; this.s2 += (this.s1 - this.s2) * smoothness; this.delta += (this.s2 - this.delta) * smoothness;
            this.bar_y = this.but_h + this.scrollbar_travel * (this.delta * this.ratio) / (this.row_count * this.row_h); p.paint();
        } else if (this.draw_timer) {window.ClearTimeout(this.draw_timer); this.draw_timer = false;}
    }

    this.but = function(dir) {
        this.check_scroll(this.scroll + (dir * -this.row_h));
        if(!this.timer_but) {var that = this; this.timer_but = window.SetInterval(function() {if (that.count > 6) {that.check_scroll(that.scroll + (dir * -that.row_h));} else that.count++;}, 40);}
    }
}
var alb_scrollbar = new scrollbar(), art_scrollbar = new scrollbar();

function button_manager() {
    var amBioBtn = "", amlfmBioBtn = "", amlfmRevBtn = "", amRevBtn = "", drawTxt = "", lfmamBioBtn = "", lfmBioBtn = "", lfmamRevBtn = "", lfmRevBtn = ""; if (ui.BtnName) {amBioBtn = window.GetProperty("ADV.Heading BtnName Biography [AllMusic]", "allmusic"); amRevBtn = window.GetProperty("ADV.Heading BtnName Review [AllMusic]", "allmusic"); lfmBioBtn = window.GetProperty("ADV.Heading BtnName Biography [Last.fm]", "last.fm"); lfmRevBtn = window.GetProperty("ADV.Heading BtnName Review [Last.fm]", "last.fm"); amlfmBioBtn = amBioBtn + " | " + lfmBioBtn; amlfmRevBtn = amRevBtn + " | " + lfmRevBtn; lfmamBioBtn = lfmBioBtn + " | " + amBioBtn; lfmamRevBtn = lfmRevBtn + " | " + amRevBtn;}
    var aBioBtn = amBioBtn, alBioBtn = amlfmBioBtn, lBioBtn = lfmBioBtn, laBioBtn = lfmamBioBtn;
    var arrow_sy = window.GetProperty(" Scrollbar Arrow Custom: Icon // Examples", "\uE0A0 // \u25B2 \uE014 \u2B9D \uE098 \uE09C \uE0A0 \u2BC5 \u23EB \u23F6 \u290A \uE018 \uE010 \uE0E4"), arrow_symb = 0; if (window.GetProperty(" Scrollbar Arrow Custom", false)) try {arrow_symb = arrow_sy.replace(/\s+/g, "").charAt(0);} catch (e) {arrow_symb = 0} if (!arrow_symb.length) arrow_symb = 0;
    var custom_col = window.GetProperty("_CUSTOM COLOURS/FONTS: USE", false), cust_icon_font = window.GetProperty("_Custom.Font Icon [Scroll] (Name,Style[0or1])", "Segoe UI Symbol,0"), icon_f_name= "Segoe UI", icon_f_style = 0, pad = Math.min(Math.max(window.GetProperty(" Scrollbar Arrow Custom: Icon: Vertical Offset %", -24) / 100, -0.5), 0.3);
    if (custom_col) {if (cust_icon_font.length) {cust_icon_font = cust_icon_font.split(","); try {var st = Math.round(parseFloat(cust_icon_font[1])); if (!st) st = 0; var font_test = gdi.Font(cust_icon_font[0], 16, st); icon_f_name = cust_icon_font[0]; icon_f_style = st;} catch(e) {p.trace("JScript Panel is unable to use your scroll icon font. Using Segoe UI instead");}}}
    var b_x, b3 = ["alb_scrollDn", "alb_scrollUp", "art_scrollDn", "art_scrollUp"], but_tt = window.CreateTooltip("Segoe UI", 15 * ui.scale * window.GetProperty(" Zoom Tooltip (%)", 100) / 100, 0), byDn, byUp, j = 0, m = false, mt = [], name_w = 0, orig_mt_sz = 15 * ui.scale, scr = [], scrollBut_x, scrollDn_y, scrollUp_y, src_fs = 37, src_h = 19, src_w = 50; this.btns = []; this.b = null; this.r_h1 = 0; this.r_h2 = 0; this.r_w1 = 0; this.r_w2 = 0;
    if (!window.GetProperty("SYSTEM.Zoom Update", false) && window.GetProperty("SYSTEM.Software Notice Checked")) window.SetProperty(" Zoom Button Size (%)", window.GetProperty(" Zoom Button Size (%)", 100) / ui.scale); window.SetProperty("SYSTEM.Zoom Update", true);
    var zoom = window.GetProperty(" Zoom Button Size (%)", 100), zoom_mt_sz = Math.max(Math.round(orig_mt_sz * zoom / 100), 7);
    var scale = Math.round(zoom_mt_sz / orig_mt_sz * 100), scc = 2, sp_w = []; window.SetProperty(" Zoom Button Size (%)", scale);

    var scroll_alb = function() {return ui.scrollbar_show && !img.artistart && !p.img_only && t.alb_txt && alb_scrollbar.scrollable_lines > 0}
    var scroll_art = function() {return ui.scrollbar_show && img.artistart && !p.img_only && t.art_txt && art_scrollbar.scrollable_lines > 0}
    this.create_mt = function() {var col = [ui.textcol & 0x44ffffff, ui.textcol & 0x99ffffff, ui.textcol], g, sz = Math.max(Math.round(20 * scale / 100), 20), sc = sz / 100; for (j = 0; j < 3; j++) {mt[j] = gdi.CreateImage(sz, sz); g = mt[j].GetGraphics(); g.SetTextRenderingHint(3); g.SetSmoothingMode(2); g.FillPolygon(col[j], 1, [50 * sc, 0, 100 * sc, 76 * sc, 0, 76 * sc]); g.SetSmoothingMode(0); mt[j].ReleaseGraphics(g);}}; this.create_mt();
    this.draw = function(gr) {try {for (var i in this.btns) {if (scroll_alb()) for (j = 0; j < 2; j++) if (i == b3[j]) this.btns[i].draw(gr); if (scroll_art()) for (j = 2; j < 4; j++) if (i == b3[j]) this.btns[i].draw(gr); if (p.mul_item && (img.artistart && i == "mt" || !img.artistart && i == "mt")) this.btns[i].draw(gr); if (ui.heading && t.head && !p.img_only && i == "src") this.btns[i].draw(gr);}} catch (e) {}}
	this.lbtn_dn = function(x, y) {if (!this.b) return false; if (ui.scrollbar_show) for (j = 0; j < b3.length; j++) if (this.b == b3[j]) {if (this.btns[this.b].trace(x, y)) this.btns[this.b].down = true; this.btns[this.b].changestate("down");} this.btns[this.b].lbtn_dn(x, y); return true;}
    this.lbtn_up = function(x, y) {if (!this.b) return false; if (ui.scrollbar_show) for (j = 0; j < b3.length; j++) {this.btns[b3[j]].down = false; if (this.b == b3[j]) this.btns[this.b].changestate(this.btns[this.b].trace(x, y) ? "hover" : "normal");} this.move(x, y); if (!this.b) return false; this.btns[this.b].lbtn_up(x, y); return true;}
	this.leave = function() {if (this.b) this.btns[this.b].changestate("normal"); this.b = null; tooltip("");}
    this.on_script_unload = function() {tooltip("");}
    this.ratingImages = []; if (ui.stars == 1 && ui.lfmTheme) this.ratingImagesLfm = []; 
    var tooltip = function(n) {if (but_tt.text == n) return; but_tt.text = n; but_tt.activate();}

    this.create_images = function() {
        var alpha = [75, 192, 228], col = [ui.textcol & 0x44ffffff, ui.textcol & 0x99ffffff, ui.textcol], g, sz = arrow_symb == 0 ? Math.max(Math.round(ui.but_h * 1.666667), 1) : 100, sc = sz / 100;
        for (j = 0; j < 3; j++) {
            scr[j] = gdi.CreateImage(sz, sz); g = scr[j].GetGraphics(); g.SetTextRenderingHint(3); g.SetSmoothingMode(2);
            if (ui.scr_col) {arrow_symb == 0 ? g.FillPolygon(col[j], 1, [50 * sc, 0, 100 * sc, 76 * sc, 0, 76 * sc]) : g.DrawString(arrow_symb, gdi.Font(icon_f_name, sz, icon_f_style), col[j], 0, sz * pad, sz, sz, StringFormat(1, 1));}
            else {arrow_symb == 0 ? g.FillPolygon(RGBA(ui.ct, ui.ct, ui.ct, alpha[j]), 1, [50 * sc, 0, 100 * sc, 76 * sc, 0, 76 * sc]) : g.DrawString(arrow_symb, gdi.Font(icon_f_name, sz, icon_f_style), RGBA(ui.ct, ui.ct, ui.ct, alpha[j]), 0, sz * pad, sz, sz, StringFormat(1, 1));}
            g.SetSmoothingMode(0); scr[j].ReleaseGraphics(g);
    }}; this.create_images();
    
    var DrawPolyStar = function (gr, x, y, out_radius, in_radius, points, line_thickness, line_color, fill_color, angle, opacity) {
        if(!opacity && opacity != 0) opacity = 255; var point_arr = [], r = 0;
        for (var i = 0; i != points; i++) {i % 2 ? r = Math.round((out_radius-line_thickness * 4) / 2) / in_radius : r = Math.round((out_radius-line_thickness * 4) / 2); var x_point = Math.floor(r * Math.cos(Math.PI * i / points * 2 - Math.PI / 2)), y_point = Math.ceil(r * Math.sin(Math.PI * i / points * 2 - Math.PI / 2)); point_arr.push(x_point + out_radius/2); point_arr.push(y_point + out_radius/2);}
        var img = gdi.CreateImage(out_radius, out_radius), gb = img.GetGraphics();
        gb.SetSmoothingMode(2); gb.FillPolygon(fill_color, 1, point_arr); if(line_thickness > 0) gb.DrawPolygon(line_color, line_thickness, point_arr); img.ReleaseGraphics(gb); 
        gr.DrawImage(img, x, y, out_radius, out_radius, 0, 0, out_radius, out_radius, angle, opacity);
    }

	this.SetRatingImages = function(width, height, on_color, off_color, border_color, lfm) {
        width = width * scc; height = height * scc;
		var real_rating = -1, star_height = height, star_indent = 2, star_padding = -1, star_size = height;
		while (star_padding <=0) {star_size = star_height; star_padding = Math.round((width - 5 * star_size) / 4); star_height--;}
		if(star_height < height) var star_vpadding = Math.floor((height - star_height) / 2);
		for (var rating = 0; rating < 11; rating++) {
			real_rating = rating / 2;
			if (Math.round(real_rating) != real_rating) {				
				var img_off = gdi.CreateImage(width, height), gb = img_off.GetGraphics(); for (var i = 0; i < 5; i++) DrawPolyStar(gb, i * (star_size + star_padding), star_vpadding, star_size, star_indent, 10, 0, border_color, off_color); img_off.ReleaseGraphics(gb);
				var img_on = gdi.CreateImage(width, height); gb = img_on.GetGraphics(); for (i = 0; i < 5; i++) DrawPolyStar(gb, i * (star_size + star_padding), star_vpadding, star_size, star_indent, 10, 0, border_color, on_color); img_on.ReleaseGraphics(gb);
				var half_mask_left = gdi.CreateImage(width, height); gb = half_mask_left.GetGraphics(); gb.FillSolidRect(0, 0, width, height, RGBA(255, 255, 255, 255)); gb.FillSolidRect(0, 0, Math.round(width * rating / 10), height, RGBA(0, 0, 0, 255)); half_mask_left.ReleaseGraphics(gb);
				var half_mask_right = gdi.CreateImage(width, height); gb = half_mask_right.GetGraphics(); gb.FillSolidRect(0, 0, width, height, RGBA(255, 255, 255, 255)); gb.FillSolidRect(Math.round(width * rating / 10), 0, width - Math.round(width * rating / 10), height, RGBA(0, 0, 0, 255)); half_mask_right.ReleaseGraphics(gb);
				img_on.ApplyMask(half_mask_left); img_off.ApplyMask(half_mask_right);
				var img = gdi.CreateImage(width, height); gb = img.GetGraphics(); gb.DrawImage(img_off, 0, 0, width, height, 0, 0, width, height); gb.DrawImage(img_on, 0, 0, width, height, 0, 0, width, height); img.ReleaseGraphics(gb);
			} else {var img = gdi.CreateImage(width, height), gb = img.GetGraphics(); for (var i = 0; i < 5; i++) DrawPolyStar(gb, i * (star_size + star_padding), star_vpadding, star_size, star_indent, 10, 0, border_color, i < real_rating ? on_color : off_color); img.ReleaseGraphics(gb);}
			!lfm ? this.ratingImages[rating] = img : this.ratingImagesLfm[rating] = img;
		}
        if (!lfm) {this.r_w1 = this.ratingImages[10].Width; this.r_w2 = this.r_w1 / scc; this.r_h1 = this.ratingImages[10].Height; this.r_h2 = this.r_h1 / scc;}
	}
    
     this.create_stars = function() {
        try {var fs = ui.head.Size; g = gdi.CreateImage(1, 1), gb = g.GetGraphics();
        src_fs = Math.min(Math.max(Math.round(fs * 0.47 + ui.srcSizeAdjust), ui.stars != 1 ? 10 : 12), fs); 
        src_h = gb.CalcTextHeight("allmusic", gdi.Font("Segoe UI", src_fs, 1)); 
        if (ui.stars == 1) this.SetRatingImages(Math.round(src_h / 1.5) * 5, Math.round(src_h / 1.5), ui.rating_icon_on, ui.rating_icon_off, ui.rating_icon_border, false);
        else if (ui.stars == 2) {this.SetRatingImages(Math.round(ui.font_h / 1.75) * 5, Math.round(ui.font_h / 1.75), ui.rating_icon_on, ui.rating_icon_off, ui.rating_icon_border, false);}
        if (ui.stars == 1 && ui.lfmTheme) this.SetRatingImages(Math.round(src_h / 1.5) * 5, Math.round(src_h / 1.5), RGBA(225, 225, 245, 255), RGB(225, 225, 245, 60), ui.rating_icon_border, true);
        var sp_arr = [" ", amRevBtn, lfmRevBtn, amBioBtn, lfmBioBtn, amlfmRevBtn, amlfmBioBtn];
        for (var i = 0; i < 7; i++) sp_w[i] = gb.CalcTextWidth(sp_arr[i], gdi.Font("Segoe UI", src_fs, 1));
        m = (/[gjpqy]/).test(amRevBtn+lfmRevBtn+amBioBtn+lfmBioBtn);
        g.ReleaseGraphics(gb); g.Dispose();} catch (e) {}
    }

	this.move = function(x, y) {
        if (this.b && this.btns[this.b].down == true || tb.down) return; var b = null, hand = false;
        for (var i in this.btns) {if (scroll_alb()) for (j = 0; j < 2; j++) if (i == b3[j] && this.btns[i].trace(x, y)) b = i; if (scroll_art()) for (j = 2; j < 4; j++) if (i == b3[j] && this.btns[i].trace(x, y)) b = i; if ((img.artistart && i == "mt" || !img.artistart && i == "mt") && this.btns[i].trace(x, y) || ui.heading && t.head && !p.img_only && i == "src" && this.btns[i].trace(x, y)) {b = i; hand = true;}}
        window.SetCursor(hand ? 32649 : 32512); if (this.b == b) return this.b; if (b) this.btns[b].changestate("hover"); if (this.b) this.btns[this.b].changestate("normal"); this.b = b; if (!this.b) tooltip("");
		return this.b;
	}

    this.wheel = function(step) {
        if (!p.mul_item || !this.btns["mt"] || !this.btns["mt"].trace(p.m_x, p.m_y)) return;
        zoom_mt_sz += step; zoom_mt_sz = Math.min(Math.max(zoom_mt_sz, 7), 100);
        window.RepaintRect(this.btns["mt"].x, this.btns["mt"].y, this.btns["mt"].w, this.btns["mt"].h);
        scale = Math.round(zoom_mt_sz / orig_mt_sz * 100); this.create_mt(); this.refresh(true); window.SetProperty(" Zoom Button Size (%)", scale);
    }

    var btn = function(x, y, w, h, type, ft, txt, stat, img_src, down, l_dn, l_up, tooltext) {
        var k = 0, l = img.artistart && t.bio_allmusic || !img.artistart && t.alb_allmusic ? 1 : 0, r = ui.stars == 1 && !img.artistart && (t.alb_allmusic && (!t.btnRevBoth ? t.rating != -1 : t.avgRating != -1) || !t.alb_allmusic && (!t.btnRevBoth ? t.l_rating != -1 : t.avgRating != -1));
        this.draw = function (gr) {
            switch (type) {
                case 5: ui.theme.SetPartAndStateId(1, this.img); ui.theme.DrawThemeBackground(gr, this.x, this.y, this.w, this.h); break;
                case 6:
                    if (ui.src < 2) {var dh = ui.src ? (r || drawTxt.trim() ? ui.BtnBg ? "   " : "  " : "") + t.heading + t.na : t.heading + t.na, dx1 = this.x + stat, dx2 = this.x;} else {var dh = t.heading + t.na, dx1 = this.x, dx2 = p.text_l + p.text_w - stat;}
                    gr.GdiDrawText(dh, ui.head, ui.headCol ? ui.textcol_h : ui.textcol, dx1, this.y, this.w - stat - (ui.src == 2 ? 10 : 0), this.h, t.lc);
                    switch (true) {
                        case ui.heading_line == 1: gr.DrawLine(this.x, this.y + ui.head_ln_h, this.x + p.text_w, this.y + ui.head_ln_h, 1, ui.linecol); break;
                        case ui.heading_line == 2: var dh_w = gr.CalcTextWidth(dh, ui.head) + sp_w[0] * 2; if (ui.src == 2 && dh_w < p.text_w - stat - sp_w[0] * 3) gr.DrawLine(this.x + dh_w, Math.round(this.y + this.h / 2), this.x + p.text_w - stat - sp_w[0] * 3, Math.round(this.y + this.h / 2), 1, ui.titlelinecol); if (ui.src < 2 && stat + sp_w[0] * 2 + dh_w < p.text_w) gr.DrawLine(dx1 + dh_w, Math.ceil(this.y + this.h / 2), this.x + p.text_w, Math.ceil(this.y + this.h / 2), 1, ui.titlelinecol); break;
                    } if (!ui.src || (!r && !drawTxt.trim())) break;
                    if (ui.BtnBg) {
                        var c1 = [RGBA(210, 19, 9, 114), ui.blend1], c2 = [RGBA(210, 19, 9, 228), ui.blend1], c3 = [,,RGBA(244, 31, 19, 255), ui.blend2], c4 = !l && !k && ui.lfmTheme ? 0 : (l || !ui.lfmTheme) && !k ? 1 : !l && k && ui.lfmTheme ? 2 : 3; gr.SetSmoothingMode(2);
                        gr.FillRoundRect(dx2, ft - (m ? 1 : 0), stat, src_h + (m ? 2 : 0), 2, 2, c1[c4]); 
                        gr.FillRoundRect(dx2, ft - (m ? 1 : 0), stat, src_h + (m ? 2 : 0), 2, 2, c4 < 2 ? c2[c4] : c3[c4]);
                        if (l || !ui.lfmTheme) gr.DrawRoundRect(dx2, ft - (m ? 1 : 0), stat, src_h + (m ? 2 : 0), 2, 2, 1, ui.blend3);
                    }
                    gr.gdiDrawText(drawTxt, gdi.Font("Segoe UI", txt, 1), this.img, dx2, ft, stat, src_h, !r ? t.cc : t.lc);
                    if (r) {gr.DrawImage(t.alb_allmusic ? but.ratingImages[!t.btnRevBoth ? t.rating : t.avgRating] : ui.BtnBg && ui.lfmTheme ? but.ratingImagesLfm[!t.btnRevBoth ? t.l_rating : t.avgRating] : but.ratingImages[!t.btnRevBoth? t.l_rating : t.avgRating], ui.src == 2 ? p.text_l + p.text_w - but.r_w2 - (ui.BtnBg ? sp_w[0] : 0) : dx2 + name_w, ft + (Math.round(src_h - but.r_h2) / 2), but.r_w2, but.r_h2, 0, 0, but.r_w1, but.r_h1, 0, 255);}
                    break;
                case 7:
                if (this.img) gr.DrawImage(this.img, this.x, this.y, this.w / 1.5, this.h / 1.5, 0, 0, this.img.Width, this.img.Height, 180); break;
                default: if (this.img) gr.DrawImage(this.img, this.x + ft, txt, stat, stat, 0, 0, this.img.Width, this.img.Height, type == 1 || type == 3 ? 0 : 180); break;
            }
        }

        this.trace = function(x, y) {return x > this.x && x < this.x + this.w && y > this.y && y < this.y + this.h;}
        this.lbtn_dn = function () {this.l_dn && this.l_dn(x, y);}
        this.lbtn_up = function () {this.l_up && this.l_up(x, y);}
        this.changestate = function(state) {switch (state) {case "hover": k = 1; this.img = this.img_hover; tooltip(this.tooltext); break; case "down": this.img = this.img_down; break; default: k = 0; this.img = this.img_normal; break;} window.RepaintRect(this.x, this.y, this.w, this.h);}
        this.x = x; this.y = y; this.w = w; this.h = h; this.l_dn = l_dn; this.l_up = l_up; this.tooltext = tooltext;
        this.img_normal = img_src.normal; this.img_hover = img_src.hover || this.img_normal; this.img_down = img_src.down || this.img_normal; this.img = this.img_normal;
    }

    this.refresh = function(upd) { try {
        var l = img.artistart && t.bio_allmusic || !img.artistart && t.alb_allmusic ? 1 : 0, r = ui.stars == 1 && !img.artistart && (t.alb_allmusic && (!t.btnRevBoth ? t.rating != -1 : t.avgRating != -1) || !t.alb_allmusic && (!t.btnRevBoth ? t.l_rating != -1 : t.avgRating != -1));
        if (upd) {b_x = p.sbar_x; byUp = Math.round(p.sbar_y); byDn = Math.round(p.sbar_y + p.sbar_h - ui.but_h); if (ui.scr_type < 2) {b_x -= 1; scrollBut_x = (ui.but_h - ui.scr_but_w) / 2; scrollUp_y = -ui.arrow_pad + byUp + (ui.but_h - 1 - ui.scr_but_w) / 2; scrollDn_y = ui.arrow_pad + byDn + (ui.but_h - 1 - ui.scr_but_w) / 2;}}
        if (ui.heading) {
            drawTxt = l ? (ui.BtnBg ? " " : "") + (!img.artistart ? (!t.btnRevBoth ? amRevBtn : amlfmRevBtn) : (!t.btnBioBoth ? amBioBtn : amlfmBioBtn)) + (ui.BtnBg || r ? " " : "") : 
            (ui.BtnBg ? " " : "") + (!img.artistart ? (!t.btnRevBoth ? lfmRevBtn : lfmamRevBtn) : (!t.btnBioBoth ? lfmBioBtn : lfmamBioBtn)) + (ui.BtnBg || r ? " " : "");
            if (!ui.src || (!r && !drawTxt.trim())) src_w = 0; else {name_w = 0; 
            if (r) name_w = t.alb_allmusic ? (!t.btnRevBoth ? sp_w[1] : sp_w[5]) : (!t.btnRevBoth ? sp_w[2] : sp_w[5]); 
            name_w = name_w + sp_w[0] * (ui.BtnBg ? (name_w ? 2 : 1) : 0); 
            src_w = r ? name_w + this.r_w2 + (drawTxt.trim() || ui.BtnBg ? sp_w[0] : 0) : drawTxt.trim() ? (img.artistart ? (t.bio_allmusic ? (!t.btnBioBoth ? sp_w[3] : sp_w[6]) : (!t.btnBioBoth ? sp_w[4] : sp_w[6])) : (t.alb_allmusic ? (!t.btnRevBoth ? sp_w[1] : sp_w[5]) : (!t.btnRevBoth ? sp_w[2] : sp_w[5]))) + sp_w[0] * (ui.BtnBg ? 2 : 0) : 0; if (!ui.BtnBg) name_w += sp_w[0] * (drawTxt.trim() ? 2 : 0);}
            this.btns.src = new btn(p.text_l, p.text_t - ui.heading_h, p.text_w, ui.font_head_h, 6, Math.min(Math.max(Math.round(p.text_t - ui.heading_h + (ui.font_head_h - src_h) / 2 + ui.src_pad), p.text_t - ui.heading_h), p.text_t - ui.heading_h + ui.font_head_h - src_h), src_fs, src_w, {normal: l || (!ui.lfmTheme || ui.lfmTheme && !ui.BtnBg) ? ui.bg || !ui.bg && !ui.trans || ui.blur_dark || ui.blur_light ? (!ui.btnCol ? ui.textcol : ui.textcol_h) : RGB(255, 255, 255) : RGB(225, 225, 245), hover: l || (!ui.lfmTheme || ui.lfmTheme && !ui.BtnBg) ?  ui.bg || !ui.bg && !ui.trans || ui.blur_dark || ui.blur_light ? ui.textcol_h : RGB(255, 255, 255) : RGB(225, 225, 245)}, false, "", function() {t.toggle(img.artistart ? (!ui.bothBio ? 0 : 6) : (!ui.bothRev ? 1 : 7)); but.refresh();}, "Switch To " + (img.artistart ? (!t.allmusic_bio ? (!t.lockBio || ui.bothBio ? "Prefer " : "") + "AllMusic" + (ui.bothBio ? " First" : "") : (!t.lockBio || ui.bothBio ? "Prefer " : "") + "Last.fm" + (ui.bothBio ? " First" : "")) : (!t.allmusic_alb ? (!t.lockRev || ui.bothRev ? "Prefer " : "") + "AllMusic"  + (ui.bothRev ? " First" : ""): (!t.lockRev || ui.bothRev ? "Prefer " : "") + "Last.fm" + (ui.bothRev ? " First" : ""))))
        }
        if (p.mul_item) this.btns.mt = new btn(0, 0, 12 * scale / 100 * 1.5, 12 * scale / 100 * 1.5, 7, "", "", "", {normal: mt[0], hover: mt[1], down: mt[2]}, false, "", function() {men.button(12 * scale / 100, 16)}, scale < 155 ? "More..." : ""); else delete this.btns.mt;
        if (ui.scrollbar_show) {
            switch (ui.scr_type) {
                case 2:
                    this.btns.alb_scrollUp = new btn(b_x, byUp, ui.but_h, ui.but_h, 5, "", "", "", {normal: 1, hover: 2, down: 3}, false, function() {alb_scrollbar.but(1);}, "", "");
                    this.btns.alb_scrollDn = new btn(b_x, byDn, ui.but_h, ui.but_h, 5, "", "", "", {normal: 5, hover: 6, down: 7}, false, function() {alb_scrollbar.but(-1);}, "", "");
                    this.btns.art_scrollUp = new btn(b_x, byUp, ui.but_h, ui.but_h, 5, "", "", "", {normal: 1, hover: 2, down: 3}, false, function() {art_scrollbar.but(1);}, "", "");
                    this.btns.art_scrollDn = new btn(b_x, byDn, ui.but_h, ui.but_h, 5, "", "", "", {normal: 5, hover: 6, down: 7}, false, function() {art_scrollbar.but(-1);}, "", "");
                    break;
                default:
                    this.btns.alb_scrollUp = new btn(b_x, byUp, ui.but_h, ui.but_h, 1, scrollBut_x, scrollUp_y, ui.scr_but_w, {normal: scr[0], hover: scr[1], down: scr[2]}, false, function() {alb_scrollbar.but(1);}, "", "");
                    this.btns.alb_scrollDn = new btn(b_x, byDn, ui.but_h, ui.but_h, 2, scrollBut_x, scrollDn_y, ui.scr_but_w, {normal: scr[0], hover: scr[1], down: scr[2]}, false, function() {alb_scrollbar.but(-1);}, "", "");
                    this.btns.art_scrollUp = new btn(b_x, byUp, ui.but_h, ui.but_h, 3, scrollBut_x, scrollUp_y, ui.scr_but_w, {normal: scr[0], hover: scr[1], down: scr[2]}, false, function() {art_scrollbar.but(1);}, "", "");
                    this.btns.art_scrollDn = new btn(b_x, byDn, ui.but_h, ui.but_h, 4, scrollBut_x, scrollDn_y, ui.scr_but_w, {normal: scr[0], hover: scr[1], down: scr[2]}, false, function() {art_scrollbar.but(-1);}, "", "");
                    break;
            }
        }} catch (e) {}
    }
}
var but = new button_manager();

function menu_object() {
    var cov_type_arr = ["Front", "Back", "Disc", "Icon", "Artist"], i = 0, MenuMap = [], MF_GRAYED = 0x00000001, MF_POPUP = 0x00000010, MF_SEPARATOR = 0x00000800, MF_STRING = 0x00000000, pl_show = window.GetProperty(" Menu Show Playlists", false); if (pl_show) pl_menu = []; this.right_up = false, style_arr = [], undoFn = "", undoPth = "", undoTxt = "#!#"; this.counter = 0; this.cyc = window.GetProperty("SYSTEM.Cycle Item", false);
    this.NewMenuItem = function(index, type, value) {MenuMap[index] = [{type: ""},{value: 0}]; MenuMap[index].type = type; MenuMap[index].value = value;}
    this.AlignTypeMenu = function(Menu, StartIndex) {var Index = StartIndex, n = p.style == 0 || p.style == 2 ? ["Left", "Centre", "Right", "Auto Align with Text"] : ["Top", "Centre", "Bottom", "Auto Align With Text"]; for (var i = 0; i < n.length; i++) {this.NewMenuItem(Index, "Align", i + 1); Menu.AppendMenuItem(MF_STRING, Index, n[i]); if (i < 3) Index++; else Menu.CheckMenuItem(Index++, img.autoAlign); if (i == 2) Menu.AppendMenuItem(MF_SEPARATOR, 0, 0);} Menu.CheckMenuRadioItem(StartIndex, StartIndex + 2, StartIndex + (p.style == 0 || p.style == 2 ? img.alignH : img.alignV)); return Index;}
    this.AlignHTypeMenu = function(Menu, StartIndex) {var Index = StartIndex, n = ["Left", "Centre", "Right"]; for (var i = 0; i < n.length; i++) {this.NewMenuItem(Index, "AlignH", i + 1); Menu.AppendMenuItem(MF_STRING, Index, n[i]); Index++;} Menu.CheckMenuRadioItem(StartIndex, StartIndex + 2, StartIndex + img.alignH); return Index;}
    this.AlignVTypeMenu = function(Menu, StartIndex) {var Index = StartIndex, c = [!img.alignV && !img.alignAuto, img.alignV == 1 && !img.alignAuto, img.alignV == 2 && !img.alignAuto, img.alignAuto], n = ["Top", "Centre", "Bottom", "Auto"]; for (var i = 0; i < n.length; i++) {this.NewMenuItem(Index, "AlignV", i + 1); Menu.AppendMenuItem(MF_STRING, Index, n[i]); Index++; Menu.CheckMenuRadioItem(StartIndex + i, StartIndex + i, StartIndex + i + 1 - c[i]); if (i == 2) Menu.AppendMenuItem(MF_SEPARATOR, 0, 0);} return Index;}
    this.BiographyTypeMenu = function(Menu, StartIndex) {var Index = StartIndex;this.NewMenuItem(Index, "Sources", 1); Index++; return Index;}
    this.BiogTypeMenu = function(Menu, StartIndex) {var Index = StartIndex, c = [p.mul_item, p.cyc, false, !p.focus, false, false], n = ["Show More Items Button", "Auto Cycle Photo", "Cycle Time...", "Now Playing", "Force Update", "Server Settings..."]; for (var i = 0; i < n.length; i++) {this.NewMenuItem(Index, "Sources", i + 17); Menu.AppendMenuItem(MF_STRING, Index, n[i]); Menu.CheckMenuItem(Index++, c[i]); if (i != 1 && i < 5) Menu.AppendMenuItem(MF_SEPARATOR, 0, 0);} return Index;}
    this.BioTypeMenu = function(Menu, StartIndex) {var Index = StartIndex, c = [t.allmusic_bio && !ui.bothBio, !t.allmusic_bio && !ui.bothBio, ui.bothBio, t.lockBio], n = [(!t.lockBio ? "Prefer " : "") + "AllMusic", (!t.lockBio ? "Prefer " : "") + "Last.fm", "Prefer Both", "Lock To Single Source"]; for (var i = 0; i < n.length; i++) {this.NewMenuItem(Index, "Sources", i + 2); Menu.AppendMenuItem((i < 2 || i == 3) && ui.bothBio ? MF_GRAYED : MF_STRING, Index, n[i]); if (i > 1) Menu.CheckMenuItem(Index++, c[i]); else {Index++; Menu.CheckMenuRadioItem(StartIndex + i, StartIndex + i, StartIndex + i + 1 - c[i]);} if (i == 1 || i == 2) Menu.AppendMenuItem(MF_SEPARATOR, 0, 0);} return Index;}
    this.BorderTypeMenu = function(Menu, StartIndex) {var Index = StartIndex, c = [img.border == 1 || img.border == 3, img.border > 1], n = ["Border", "Shadow"]; for (var i = 0; i < n.length; i++) {this.NewMenuItem(Index, "Border", i + 1); Menu.AppendMenuItem(!img.reflection || i != 1 ? MF_STRING : MF_GRAYED, Index, n[i]); Menu.CheckMenuItem(Index++, c[i]);} return Index;}
    this.CovTypeMenu = function(Menu, StartIndex) {var Index = StartIndex, c = [p.lfm_img, !p.lfm_img, false, false], n = cov_type_arr; for (var i = 0; i < n.length; i++) {this.NewMenuItem(Index, "Sources", i + 12); Menu.AppendMenuItem(MF_STRING, Index, n[i]); Index++;} Menu.CheckMenuRadioItem(StartIndex, StartIndex + 4, StartIndex + img.covType); return Index;}
    this.CropTypeMenu = function(Menu, StartIndex) {var Index = StartIndex, c = [img.artCropImgOnly, img.artCropDual, img.covCropImgOnly, img.covCropDual], n = ["Photo [Image Only]", "Photo [Dual Mode]", "Cover [Image Only]", "Cover [Dual Mode]"]; for (var i = 0; i < n.length; i++) {this.NewMenuItem(Index, "Crop", i + 1); Menu.AppendMenuItem(MF_STRING, Index, n[i]); Menu.CheckMenuItem(Index++, c[i]); if (i == 1) Menu.AppendMenuItem(MF_SEPARATOR, 0, 0);} return Index;}
    this.DefaultTypeMenu = function(Menu, StartIndex) {var Index = StartIndex, n = ["Panel Properties", "Configure..."]; Menu.AppendMenuItem(MF_SEPARATOR, 0, 0); for (var i = 0; i < 2; i++) {this.NewMenuItem(Index, "Default", i + 1); if (!i || i && utils.IsKeyPressed(0x10)) Menu.AppendMenuItem(MF_STRING, Index++, n[i]);} return Index;}
    this.DisplayTypeMenu = function(Menu, StartIndex) {var Index = StartIndex, n = [!p.imgText ? "Auto Display" : "Image+Text", "Image Only", "Text Only"]; for (var i = 0; i < n.length; i++) {this.NewMenuItem(Index, "Display", i + 1); Menu.AppendMenuItem(i != 1 || !p.autoEnlarge ? MF_STRING : MF_GRAYED, Index, n[i]); Index++; if (i == 2) Menu.AppendMenuItem(MF_SEPARATOR, 0, 0);} Menu.CheckMenuRadioItem(StartIndex, StartIndex + 2, StartIndex + (!p.img_only && !p.text_only ? 0 : p.img_only ? 1 : 2)); return Index;}
    this.fresh = function() {this.counter++; if (this.counter > p.cycle_item) this.counter = 0; if (t.block() || !this.cyc || this.counter != p.cycle_item || img.artistart && p.artists.length < 2 || !img.artistart && p.albums.length < 2 || (fb.IsPlaying ? fb.PlaybackTime - timer.men_step < p.cycle_item / 2 : false) || ui.zoom()) return; this.wheel(1, true);}
    this.HeadingTypeMenu= function(Menu, StartIndex) {var Index = StartIndex, c = [ui.heading, ui.src == 2, ui.src == 1, ui.heading_line == 1, ui.heading_line == 2, !ui.custHeadFont ? ui.head_font_style == 1 : ui.cust_h_f[2] == 1, !ui.custHeadFont ? ui.head_font_style == 2 : ui.cust_h_f[2] == 2, !ui.custHeadFont ? ui.head_font_style == 3 : ui.cust_h_f[2] == 3], n = ["Show", "Button Right", "Button Left", "Line Bottom", "Line Center", "Bold", "Italic", "Bold Italic"]; for (var i = 0; i < n.length; i++) {this.NewMenuItem(Index, "Heading", i + 1); Menu.AppendMenuItem(!i || ui.heading ? MF_STRING : MF_GRAYED, Index, n[i]); Menu.CheckMenuItem(Index++, c[i]); if (!i || i == 2 || i == 4) Menu.AppendMenuItem(MF_SEPARATOR, 0, 0);} return Index;}
    this.ImageTypeMenu = function(Menu, StartIndex) {var Index = StartIndex, n = ["Enlarge on Mouse Over", "Smooth Transition"], c = [p.autoEnlarge, img.smoothTrans]; for (var i = 0; i < n.length; i++) {this.NewMenuItem(Index, "Image", i + 1); Menu.AppendMenuItem(MF_STRING, Index, n[i]); Menu.CheckMenuItem(Index++, c[i]); if (i) Menu.AppendMenuItem(MF_SEPARATOR, 0, 0);} return Index;}
    this.LangTypeMenu= function(Menu, StartIndex) {var Index = StartIndex, n = p.langArr; for (var i = 0; i < n.length; i++) {this.NewMenuItem(Index, "Language", i + 1); Menu.AppendMenuItem(MF_STRING, Index, n[i]); Index++; Menu.CheckMenuRadioItem(StartIndex + i, StartIndex + i, StartIndex + p.lfmLang_ix);} return Index;}
    this.LayoutTypeMenu = function(Menu, StartIndex) {if (p.sameStyle) {style_arr = p.style_arr.slice(); style_arr.push("Use Same Style for Biography && Review");} var Index = StartIndex, n = p.sameStyle ? style_arr : ["Use Same Style for Biography && Review"]; for (var i = 0; i < n.length; i++) {this.NewMenuItem(Index, "Layout", i + 1); Menu.AppendMenuItem(MF_STRING, Index, n[i]); if (i == (p.sameStyle ? n.length - 1 : 0)) Menu.CheckMenuItem(Index++, p.sameStyle); else Index++; if (p.sameStyle && (i == 4 || i == n.length - 2 || i == n.length - 1) || !p.sameStyle) Menu.AppendMenuItem(MF_SEPARATOR, 0, 0);} if (p.sameStyle) Menu.CheckMenuRadioItem(StartIndex, StartIndex + n.length - 2, StartIndex + p.style); return Index;}
    this.LayoutBioTypeMenu = function(Menu, StartIndex) {var Index = StartIndex, n = p.style_arr; for (var i = 0; i < n.length; i++) {this.NewMenuItem(Index, "BioStyle", i + 1); Menu.AppendMenuItem(MF_STRING, Index, n[i]); Index++; if (n.length > 5 && i == 4) Menu.AppendMenuItem(MF_SEPARATOR, 0, 0);} Menu.CheckMenuRadioItem(StartIndex, StartIndex + n.length - 1, StartIndex + p.bioStyle); return Index;}
    this.LayoutRevTypeMenu = function(Menu, StartIndex) {var Index = StartIndex, n = p.style_arr; for (var i = 0; i < n.length; i++) {this.NewMenuItem(Index, "RevStyle", i + 1); Menu.AppendMenuItem(MF_STRING, Index, n[i]); Index++; if (n.length > 5 && i == 4) Menu.AppendMenuItem(MF_SEPARATOR, 0, 0);} Menu.CheckMenuRadioItem(StartIndex, StartIndex + n.length - 1, StartIndex + p.revStyle); return Index;}
    this.MoreAlbMenu = function(Menu, StartIndex) {var Index = StartIndex; var n = ["Manual Cycle: Wheel Over Button or Image", "Auto Cycle Items", "Cycle Time..."]; for (var i = 0; i < p.albums.length; i++) {this.NewMenuItem(Index, "More-Album", i + 1); Menu.AppendMenuItem(p.albums[i].type != "label" ? MF_STRING : MF_GRAYED, Index, !i ? p.albums[i].artist.replace(/&/g, "&&") + " - " + p.albums[i].album.replace(/&/g, "&&") : p.albums[i].album.replace(/&/g, "&&")); Index++; if (!i || p.albums[i].type == "albumend" || p.albums[i].type == "label") Menu.AppendMenuItem(MF_SEPARATOR, 0, 0);} Menu.CheckMenuRadioItem(StartIndex, StartIndex + p.albums.length, StartIndex + p.alb_ix); for (i = 0; i < n.length; i++) {this.NewMenuItem(Index, "More-Album", p.albums.length + i + 1); Menu.AppendMenuItem(!i ? MF_GRAYED : MF_STRING, Index, n[i]); if (i == 1) Menu.CheckMenuItem(Index++, this.cyc); else Index++; if (!i) Menu.AppendMenuItem(MF_SEPARATOR, 0, 0);} return Index;}
    this.MoreArtMenu = function(Menu, StartIndex) {var Index = StartIndex; var n = ["Manual Cycle: Wheel Over Button", "Auto Cycle Items", "Cycle Time..."]; for (var i = 0; i < p.artists.length; i++) {this.NewMenuItem(Index, "More-Artist", i + 1); Menu.AppendMenuItem(p.artists[i].type != "label" ? MF_STRING : MF_GRAYED, Index, p.artists[i].name.replace(/&/g, "&&") + p.artists[i].field.replace(/&/g, "&&")); Index++; if (!i || p.artists[i].type == "similarend" || p.artists[i].type == "label"|| p.artists[i].type == "tagend") Menu.AppendMenuItem(MF_SEPARATOR, 0, 0);} Menu.CheckMenuRadioItem(StartIndex, StartIndex + p.artists.length, StartIndex + p.art_ix); for (i = 0; i < n.length; i++) {this.NewMenuItem(Index, "More-Artist", p.artists.length + i + 1); Menu.AppendMenuItem(!i ? MF_GRAYED : MF_STRING, Index, n[i]); if (i == 1) Menu.CheckMenuItem(Index++, this.cyc); else Index++; if (!i) Menu.AppendMenuItem(MF_SEPARATOR, 0, 0); } return Index;}
    this.PasteTypeMenu = function(Menu, StartIndex) {var Index = StartIndex, n = ["Biography [AllMusic Location]", "Biography [Last.fm Location]", "Review [AllMusic Location]", "Review [Last.fm Location]", "Open Last Edited", "Undo"]; for (var i = 0; i < n.length; i++) {this.NewMenuItem(Index, "Paste", i + 1); Menu.AppendMenuItem(!i && !t.amBioPth()[2] || i == 1 && !t.lfmBioPth()[2] || i == 2 && !t.amRevPth()[2] || i == 3 && !t.lfmRevPth()[2] || i == 4 && !undoFn || i == 5 && undoTxt == "#!#" ? MF_GRAYED : MF_STRING, Index, n[i]); Index++; if (i == 1 || i == 3 || i == 4) Menu.AppendMenuItem(MF_SEPARATOR, 0, 0);} return Index;}
    this.PhotoTypeMenu = function(Menu, StartIndex) {var Index = StartIndex, c = [p.lfm_img, !p.lfm_img], n = ["Last.fm", "Artist"]; for (var i = 0; i < n.length; i++) {this.NewMenuItem(Index, "Sources", i + 10); Menu.AppendMenuItem(MF_STRING, Index, n[i]); Index++; Menu.CheckMenuRadioItem(StartIndex + i, StartIndex + i, StartIndex + i + 1 - c[i]);} return Index;}
    this.playlists_changed = function() {if (!pl_show) return; pl_menu = []; for (var i = 0; i < plman.PlaylistCount; i++) pl_menu.push({name:plman.GetPlaylistName(i).replace(/&/g, "&&"), ix:i});}; this.playlists_changed();
    this.PlaylistTypeMenu = function(i, Menu, StartIndex) {if (!pl_show) return; Index = StartIndex; for (var j = i * 30; j < Math.min(pl_menu.length, 30 + i * 30); j++) {this.NewMenuItem(Index, "Playlists", j); Menu.AppendMenuItem(MF_STRING, Index, pl_menu[j].name); Index++;} Menu.CheckMenuRadioItem(StartIndex, StartIndex + 30 + i * 30, StartIndex - i * 30 + plman.ActivePlaylist); return Index;}
    this.ReflTypeMenu = function(Menu, StartIndex) {var Index = StartIndex, n = ["Show", "Auto Position", "Top", "Left", "Bottom", "Right"]; for (var i = 0; i < n.length; i++) {this.NewMenuItem(Index, "Reflection", i + 1); Menu.AppendMenuItem(!i || img.reflection ? MF_STRING : MF_GRAYED, Index, n[i]); if (!i) Menu.CheckMenuItem(Index++, img.reflection); else Index++; if (!i) Menu.AppendMenuItem(MF_SEPARATOR, 0, 0);} Menu.CheckMenuRadioItem(StartIndex + 1, StartIndex + 5, StartIndex + img.reflectionType + 1); return Index;}
    this.ReloadTypeMenu = function(Menu, StartIndex) {var Index = StartIndex; this.NewMenuItem(Index, "Theme", 5); Menu.AppendMenuItem(MF_STRING, Index, "Reload"); Index++; return Index;}
    this.RevTypeMenu = function(Menu, StartIndex) {var Index = StartIndex, c = [t.allmusic_alb && !ui.bothRev, !t.allmusic_alb && !ui.bothRev, ui.bothRev, t.lockRev], n = [(!t.lockRev ? "Prefer " : "") + "AllMusic", (!t.lockRev ? "Prefer " : "") + "Last.fm", "Prefer Both", "Lock To Single Source"]; for (var i = 0; i < n.length; i++) {this.NewMenuItem(Index, "Sources", i + 6); Menu.AppendMenuItem((i < 2 || i == 3) && ui.bothRev ? MF_GRAYED : MF_STRING, Index, n[i]); if (i > 1) Menu.CheckMenuItem(Index++, c[i]); else {Index++; Menu.CheckMenuRadioItem(StartIndex + i, StartIndex + i, StartIndex + i + 1 - c[i]);} if (i == 1 || i == 2) Menu.AppendMenuItem(MF_SEPARATOR, 0, 0);} return Index;}
    this.ServerTypeMenu = function(Menu, StartIndex) {var Index = StartIndex; this.NewMenuItem(Index, "Server", 1); if (utils.IsKeyPressed(0x10)) {Menu.AppendMenuItem(MF_GRAYED, Index, "Biography Server"); Menu.AppendMenuItem(MF_SEPARATOR, 0, 0); Index++;} return Index;}
    this.StylesEditorTypeMenu = function(Menu, StartIndex) {var Index = StartIndex, n = ["Mouse Over && Press CTRL to Alter Existing Styles", "Create New Style...", "Rename Custom Style...", "Delete Custom Style...", "Export Custom Style...", "Reset Style..."]; for (var i = 0; i < n.length; i++) {this.NewMenuItem(Index, "Style", i + 1); Menu.AppendMenuItem(!i ? MF_GRAYED : i == 1 || p.style > 4 || i == 5 ? MF_STRING : MF_GRAYED, Index, n[i]); Index++; if (!i) Menu.AppendMenuItem(MF_SEPARATOR, 0, 0);} return Index;}
    this.TagsTypeMenu = function(Menu, StartIndex) {var Index = StartIndex, tags = (p.albGenre_am ? p.albGenre_am_nm + "; " : "") + (p.mood ? p.mood_nm + "; " : "") + (p.rating ? p.rating_nm + "; " : "") + (p.theme ? p.theme_nm + "; " : "") + (p.artGenre_am ? p.artGenre_am_nm + "; " : "") + (p.albGenre_lfm ? p.albGenre_lfm_nm + "; " : "") + (p.artGenre_lfm ? p.artGenre_lfm_nm + "; " : "") + (p.similar ? p.similar_nm : ""), n = ["Write Existing File Info to Tags: " + (tags ? tags.trim().replace(/;$/, "") : "No Tags Enabled in Server Settings"), "Cancel"]; for (var i = 0; i < n.length; i++) {this.NewMenuItem(Index, "Tags", i + 1); Menu.AppendMenuItem(MF_STRING, Index, n[i]); Index++; if (!i) Menu.AppendMenuItem(MF_SEPARATOR, 0, 0)} return Index;}
    this.ThemeTypeMenu = function(Menu, StartIndex) {var Index = StartIndex, c = [!ui.blur_dark && !ui.blur_blend && !ui.blur_light, ui.blur_dark, ui.blur_blend, ui.blur_light], n = ["None", "Dark", "Blend", "Light"]; for (var i = 0; i < n.length; i++) {this.NewMenuItem(Index, "Theme", i + 1); Menu.AppendMenuItem(MF_STRING, Index, n[i]); Index++; Menu.CheckMenuRadioItem(StartIndex + i, StartIndex + i, StartIndex + i + 1 - c[i]); if (!i) Menu.AppendMenuItem(MF_SEPARATOR, 0, 0);} return Index;}
    this.TitleTypeMenu= function(Menu, StartIndex) {var Index = StartIndex, c = [, , , ui.title_font_style == 1, ui.title_font_style == 2, ui.title_font_style == 3], n = ["Hide", "Auto", "Show", "Bold", "Italic", "Bold Italic"]; for (var i = 0; i < n.length; i++) {this.NewMenuItem(Index, "Title", i + 1); Menu.AppendMenuItem(MF_STRING, Index, n[i]); if (i < 3) Index++; else Menu.CheckMenuItem(Index++, c[i]); if (i == 2) Menu.AppendMenuItem(MF_SEPARATOR, 0, 0);} Menu.CheckMenuRadioItem(StartIndex, StartIndex + 2, StartIndex + t.title); return Index;}
    this.ToggleTypeMenu = function(Menu, StartIndex) {var Index = StartIndex, n = img.artistart ? "Biography: Switch To " + (!t.allmusic_bio ? (!t.lockBio || ui.bothBio ? "Prefer " : "") + "AllMusic" + (ui.bothBio ? " First" : "") : (!t.lockBio || ui.bothBio ? "Prefer " : "") + "Last.fm" + (ui.bothBio ? " First" : "")) : "Review: Switch To " + (!t.allmusic_alb ? (!t.lockRev || ui.bothRev ? "Prefer " : "") + "AllMusic" + (ui.bothRev ? " First" : "") : (!t.lockRev || ui.bothRev ? "Prefer " : "") + "Last.fm" + (ui.bothRev ? " First" : "")); this.NewMenuItem(Index, "Toggle", 1); Menu.AppendMenuItem(MF_STRING, Index, n); Index++; Menu.AppendMenuItem(MF_SEPARATOR, 0, 0); return Index;}
    this.WebTypeMenu = function(Menu, StartIndex) {var artist = p.artists.length ? p.artists[0].name : name.artist(), Index = StartIndex, n = ["Last.fm: " + artist + "...", "Last.fm: " + artist + ": Similar Artists...", "Last.fm: " + artist + ": Top Albums...", "AllMusic: " + artist + "..."]; for (var i = 0; i < n.length; i++) {this.NewMenuItem(Index, "Web", i + 1); Menu.AppendMenuItem(MF_STRING, Index, n[i]); Index++; if (i == 2) Menu.AppendMenuItem(MF_SEPARATOR, 0, 0);} return Index;}

    this.rbtn_up = function(x, y) {
        this.right_up = true; var AlignMenu = window.CreatePopupMenu(), AlignHMenu = window.CreatePopupMenu(), AlignVMenu = window.CreatePopupMenu(), BioMenu = window.CreatePopupMenu(), BiogMenu = window.CreatePopupMenu(), BiographyMenu = window.CreatePopupMenu(), CovMenu = window.CreatePopupMenu(), CropMenu = window.CreatePopupMenu(), ImageMenu = window.CreatePopupMenu(), HeadingMenu = window.CreatePopupMenu(), LangMenu = window.CreatePopupMenu(), LayoutMenu = window.CreatePopupMenu(), LayoutBioMenu = window.CreatePopupMenu(), LayoutRevMenu = window.CreatePopupMenu(), menu = window.CreatePopupMenu(), PasteMenu = window.CreatePopupMenu(), PhotoMenu = window.CreatePopupMenu(), ReflMenu = window.CreatePopupMenu(), RevMenu = window.CreatePopupMenu(), StylesEditorMenu = window.CreatePopupMenu(), TagsMenu = window.CreatePopupMenu(), ThemeMenu = window.CreatePopupMenu(), TitleMenu = window.CreatePopupMenu(); if (pl_show) var PlaylistsMenu = window.CreatePopupMenu();
        var doc = new ActiveXObject('htmlfile'), docTxt = doc.parentWindow.clipboardData.getData('text'), idx, Index = 1;
        if (p.server) Index = this.ServerTypeMenu(menu, Index);
        if (!p.img_only) Index = this.ToggleTypeMenu(menu, Index);
        Index = this.DisplayTypeMenu(menu, Index);
        Index = this.BiographyTypeMenu(BiographyMenu, Index); BiographyMenu.AppendTo(menu, MF_STRING | MF_POPUP, "Sources");
        Index = this.BioTypeMenu(BioMenu, Index); BioMenu.AppendTo(BiographyMenu, MF_STRING | MF_POPUP, "Biography: " + (t.allmusic_bio ? !ui.bothBio ? (!t.lockBio ? "Prefer " : "") + "AllMusic" : "Prefer Both" :  !ui.bothBio ? (!t.lockBio ? "Prefer " : "") + "Last.fm" : "Prefer Both" ));
        Index = this.RevTypeMenu(RevMenu, Index); RevMenu.AppendTo(BiographyMenu, MF_STRING | MF_POPUP, "Review: " + (t.allmusic_alb ? !ui.bothRev ? (!t.lockRev ? "Prefer " : "") + "AllMusic" : "Prefer Both" : !ui.bothRev ? (!t.lockRev ? "Prefer " : "") + "Last.fm" : "Prefer Both")); BiographyMenu.AppendMenuItem(MF_SEPARATOR, 0, 0);
        Index = this.PhotoTypeMenu(PhotoMenu, Index); PhotoMenu.AppendTo(BiographyMenu, MF_STRING | MF_POPUP, "Photo: " + (p.lfm_img ? "Last.fm" : "Artist"));
        Index = this.CovTypeMenu(CovMenu, Index); CovMenu.AppendTo(BiographyMenu, MF_STRING | MF_POPUP, "Cover: " + cov_type_arr[img.covType]); BiographyMenu.AppendMenuItem(MF_SEPARATOR, 0, 0);
        Index = this.PasteTypeMenu(PasteMenu, Index); PasteMenu.AppendTo(BiographyMenu, docTxt && !p.img_only ? MF_STRING : MF_GRAYED | MF_POPUP, "Paste Text From Clipboard"); BiographyMenu.AppendMenuItem(MF_SEPARATOR, 0, 0);
        Index = this.BiogTypeMenu(BiographyMenu, Index);
        Index = this.LangTypeMenu(LangMenu, Index); LangMenu.AppendTo(BiographyMenu, MF_STRING | MF_POPUP, "Last.fm Language");
        Index = this.LayoutTypeMenu(LayoutMenu, Index); LayoutMenu.AppendTo(menu, MF_STRING | MF_POPUP, "Layout");
        if (!p.sameStyle) {Index = this.LayoutBioTypeMenu(LayoutBioMenu, Index); LayoutBioMenu.AppendTo(LayoutMenu, MF_STRING, "Biography Style"); Index = this.LayoutRevTypeMenu(LayoutRevMenu, Index); LayoutRevMenu.AppendTo(LayoutMenu, MF_STRING, "Review Style"); LayoutMenu.AppendMenuItem(MF_SEPARATOR, 0, 0);}
        Index = this.StylesEditorTypeMenu(StylesEditorMenu, Index); StylesEditorMenu.AppendTo(LayoutMenu, MF_STRING, "Create && Manage Styles"); LayoutMenu.AppendMenuItem(MF_SEPARATOR, 0, 0);
        Index = this.HeadingTypeMenu(HeadingMenu, Index); HeadingMenu.AppendTo(LayoutMenu, MF_STRING | MF_POPUP, "Heading"); LayoutMenu.AppendMenuItem(MF_SEPARATOR, 0, 0);
        Index = this.TitleTypeMenu(TitleMenu, Index); TitleMenu.AppendTo(LayoutMenu, MF_STRING | MF_POPUP, "Title"); LayoutMenu.AppendMenuItem(MF_SEPARATOR, 0, 0);
        Index = this.ThemeTypeMenu(ThemeMenu, Index); ThemeMenu.AppendTo(LayoutMenu, MF_STRING | MF_POPUP, "Theme"); LayoutMenu.AppendMenuItem(MF_SEPARATOR, 0, 0);
        Index = this.ReloadTypeMenu(LayoutMenu, Index);
        Index = this.ImageTypeMenu(ImageMenu, Index); ImageMenu.AppendTo(menu, MF_STRING | MF_POPUP, "Image");
        Index = this.CropTypeMenu(CropMenu, Index); CropMenu.AppendTo(ImageMenu, MF_STRING | MF_POPUP, "Auto-Fill"); 
        if (p.style < 4) {Index = this.AlignTypeMenu(AlignMenu, Index); AlignMenu.AppendTo(ImageMenu, !p.img_only && t.text && !p.text_only ? MF_STRING : MF_GRAYED | MF_POPUP, "Alignment");}
        else {Index = this.AlignHTypeMenu(AlignHMenu, Index); AlignHMenu.AppendTo(ImageMenu, !p.img_only && t.text && !p.text_only ? MF_STRING : MF_GRAYED | MF_POPUP, "Alignment Horizontal"); Index = this.AlignVTypeMenu(AlignVMenu, Index); AlignVMenu.AppendTo(ImageMenu, !p.img_only && t.text && !p.text_only ? MF_STRING : MF_GRAYED | MF_POPUP, "Alignment Vertical");}
        Index = this.ReflTypeMenu(ReflMenu, Index); ReflMenu.AppendTo(ImageMenu, MF_STRING, "Reflection"); ImageMenu.AppendMenuItem(MF_SEPARATOR, 0, 0);
        Index = this.BorderTypeMenu(ImageMenu, Index);
        if (pl_show) {menu.AppendMenuItem(MF_SEPARATOR, 0, 0); PlaylistsMenu.AppendTo(menu, MF_STRING | MF_POPUP, "Playlists"); var pl_me = [], pl_no = Math.ceil(pl_menu.length / 30); for (var j = 0; j < pl_no; j++) {pl_me[j] = window.CreatePopupMenu(); Index = this.PlaylistTypeMenu(j, pl_me[j], Index); pl_me[j].AppendTo(PlaylistsMenu, MF_STRING | MF_POPUP, "# " + (j * 30 + 1 +  " - " + Math.min(pl_menu.length, 30 + j * 30) + (30 + j * 30 > plman.ActivePlaylist && ((j * 30) - 1) < plman.ActivePlaylist ? "  >>>" : "")));}}
        if (utils.IsKeyPressed(0x10)) {menu.AppendMenuItem(MF_SEPARATOR, 0, 0); Index = this.TagsTypeMenu(TagsMenu, Index); var handles = plman.GetPlaylistSelectedItems(plman.ActivePlaylist); TagsMenu.AppendTo(menu, handles.Count ? MF_STRING : MF_GRAYED | MF_POPUP, "Write Tags to Selected Tracks" + (handles.Count ? "" : ": N/A No Playlist Tracks Selected"));}
        Index = this.DefaultTypeMenu(menu, Index);

        idx = menu.TrackPopupMenu(x, y);
        if (idx >= 1 && idx <= Index) {
            var i = MenuMap[idx].value;
            switch (MenuMap[idx].type) {
                case "Toggle" : t.toggle(img.artistart ? (!ui.bothBio ? 0 : 6) : (!ui.bothRev ? 1 : 7)); break; case "Display": p.mode(i); break;
                case "Sources":
                    switch (i) {
                        case 2: case 3: t.toggle(0); break; case 4: t.toggle(4); break; case 5: t.toggle(2); break; case 6: case 7: t.toggle(1); break; case 8: t.toggle(5); break; case 9: t.toggle(3); break;
                        case 10: case 11: p.lfm_img = !p.lfm_img; window.SetProperty("SYSTEM.Image [Artist] Prefer Last.fm", p.lfm_img); img.a_run = true; img.get_images(); break;
                        case 12: case 13: case 14: case 15:  case 16:  img.covType = i - 12; img.get_images(); window.SetProperty("SYSTEM.Cover Type", img.covType); break;
                        case 17: p.mul_item = !p.mul_item; if (p.mul_item) p.get_multi(false); else p.artists = []; but.refresh(); t.paint(); window.SetProperty("SYSTEM.Button More Items", p.mul_item); break;
                        case 18: p.cyc = !p.cyc; window.SetProperty("SYSTEM.Image [Artist] Cycle", p.cyc); break;
                        case 19: p.setCycPhoto(); break;
                        case 20: p.focus = !p.focus; window.SetProperty("SYSTEM.Prefer Focus", p.focus); p.changed(p.focus); t.on_playback_new_track(); img.on_playback_new_track(); break;
                        case 21: p.getData(1, p.focus, "force_update_jb", 0); break;
                        case 22: var open = function(c, w) {if (!ui.run(c, w)) fb.ShowPopupMessage("Unable to launch your default text editor.", "Biography");}; open("\"" + p.bio_ini, 1); break;
                }
                break;
                case "Paste":
                    switch (i) {
                        case 1: undoPth = t.amBioPth()[0]; undoFn = t.amBioPth()[1]; undoTxt = utils.ReadTextFile(undoFn); p.buildFullPth(undoPth); p.save(undoFn, docTxt + "\r\n\r\nCustom Biography"); img.artistart = true; t.allmusic_bio = true; window.NotifyOthers("grab_txt_jb", "grab_txt_jb"); t.grab(); if (p.text_only) t.paint(); window.SetProperty("SYSTEM.Artist Art", img.artistart); window.SetProperty("SYSTEM.Allmusic Bio", t.allmusic_bio); break;
                        case 2: undoPth = t.lfmBioPth()[0]; undoFn = t.lfmBioPth()[1]; undoTxt = utils.ReadTextFile(undoFn); p.buildFullPth(undoPth); p.save(undoFn, docTxt + "\r\n\r\nCustom Biography"); img.artistart = true; t.allmusic_bio = false; window.NotifyOthers("grab_txt_jb", "grab_txt_jb"); t.grab(); if (p.text_only) t.paint(); window.SetProperty("SYSTEM.Artist Art", img.artistart); window.SetProperty("SYSTEM.Allmusic Bio", t.allmusic_bio); break;
                        case 3: undoPth = t.amRevPth()[0]; undoFn = t.amRevPth()[1]; undoTxt = utils.ReadTextFile(undoFn); p.buildFullPth(undoPth); img.artistart = false; t.allmusic_alb = true; window.NotifyOthers("grab_txt_jb", "grab_txt_jb"); t.grab(); if (p.text_only) t.paint(); window.SetProperty("SYSTEM.Artist Art", img.artistart); window.SetProperty("SYSTEM.Allmusic Alb", t.allmusic_alb); break;
                        case 4: undoPth = t.lfmRevPth()[0]; undoFn = t.lfmRevPth()[1]; undoTxt = utils.ReadTextFile(undoFn); p.buildFullPth(undoPth); p.save(undoFn, docTxt + "\r\n\r\nCustom Review"); img.artistart = false; t.allmusic_alb = false; window.NotifyOthers("grab_txt_jb", "grab_txt_jb"); t.grab(); if (p.text_only) t.paint(); window.SetProperty("SYSTEM.Artist Art", img.artistart); window.SetProperty("SYSTEM.Allmusic Alb", t.allmusic_alb); break;
                        case 5: var open = function(c, w) {if (!ui.run(c, w)) fb.ShowPopupMessage("Unable to launch your default text editor.", "Biography");}; open("\"" + undoFn, 1); break;
                        case 6: if (!undoTxt.length && p.file(undoFn)) {p.fs.DeleteFile(undoFn); window.NotifyOthers("reload_jb", "reload_jb"); if (!p.art_ix && img.artistart || !p.alb_ix && !img.artistart) window.Reload(); else {t.artistFlush(); t.albumFlush(); t.grab(); if (p.text_only) t.paint();} break;} p.buildFullPth(undoPth); p.save(undoFn, undoTxt); undoTxt = "#!#"; window.NotifyOthers("grab_txt_jb", "grab_txt_jb"); t.grab(); if (p.text_only) t.paint(); break;} break;
                case "Language": p.lfmLang_ix = i - 1; p.updIniLang(p.langArr[p.lfmLang_ix]); p.lfmLang = p.langArr[p.lfmLang_ix].toLowerCase(); p.server = true; window.NotifyOthers("not_server_jb", 0); if (p.server) {serv.setLfm(p.lfmLang); p.getData(2, p.focus, "", 1); window.NotifyOthers("new_lang_jb", "new_lang_jb");} break;
                case "Layout": if (p.sameStyle) {if (i < 6) {p.style = i - 1; t.toggle(8);} else if (i > 5 && i < style_arr.length) {p.style = i - 1; t.toggle(8);} if (i == style_arr.length) {p.sameStyle = !p.sameStyle; window.SetProperty("SYSTEM.Bio & Rev Same Style", p.sameStyle); t.toggle(8);}} else {p.sameStyle = !p.sameStyle; window.SetProperty("SYSTEM.Bio & Rev Same Style", p.sameStyle); t.toggle(8);} break;
                case "BioStyle": p.bioStyle = i - 1; t.toggle(8); break; case "RevStyle": p.revStyle = i - 1; t.toggle(8); break;
                case "Style": switch (i) {case 2: p.createStyle(); break; case 3: p.renameStyle(p.style); break; case 4: p.deleteStyle(p.style); break; case 5: p.exportStyle(p.style); break; case 6: p.resetStyle(p.style); break;} break;
                case "Heading":
                    switch (i) {
                        case 1: ui.heading = !ui.heading; t.toggle(9); window.SetProperty("SYSTEM.Heading", ui.heading); break;
                        case 2: case 3: ui.src = ui.src == 4 - i ? 0 : 4 - i; t.toggle(9); window.SetProperty("SYSTEM.Heading Button Hide-0 Left-1 Right-2", ui.src); break;
                        case 4: case 5: ui.heading_line = ui.heading_line == i - 3 ? 0 : i - 3; t.toggle(10); break;
                        case 6: !ui.custHeadFont ? (ui.head_font_style = ui.head_font_style == 1 ? 0 : 1) : (ui.cust_h_f[2] = ui.cust_h_f[2] == 1 ? 0 : 1); t.toggle(12, false); break;
                        case 7: !ui.custHeadFont ? (ui.head_font_style = ui.head_font_style == 2 ? 0 : 2) : (ui.cust_h_f[2] = ui.cust_h_f[2] == 2 ? 0 : 2); t.toggle(12, false); break;
                        case 8: !ui.custHeadFont ? (ui.head_font_style = ui.head_font_style == 3 ? 0 : 3) : (ui.cust_h_f[2] = ui.cust_h_f[2] == 3 ? 0 : 3); t.toggle(12, false); break;
                    }
                    break;
                case "Title": switch (i) {case 4: ui.title_font_style = ui.title_font_style == 1 ? 0 : 1; t.toggle(12, true); break; case 5: ui.title_font_style = ui.title_font_style == 2 ? 0 : 2; t.toggle(12, true); break; case 6: ui.title_font_style = ui.title_font_style == 3 ? 0 : 3; t.toggle(12, true); break; default: t.toggle(11, i - 1); break;} break;
                case "Theme": if (i < 5) ui.blurChange(i); else window.Reload(); break;
                case "Image": switch (i) {case 1: p.autoEnlarge = !p.autoEnlarge; window.SetProperty("SYSTEM.Image Auto Enlarge", p.autoEnlarge); break; case 2: img.smoothTrans = !img.smoothTrans; if (ui.blur) {img.clear_rs_cache(); img.get_images();} window.SetProperty("SYSTEM.Image Smooth Transition", img.smoothTrans); break;} break;
                case "Crop":
                    switch (i) {
                        case 1: img.artCropImgOnly = !img.artCropImgOnly; img.setCrop(true); img.clear_rs_cache(); img.get_images(); window.SetProperty("SYSTEM.Photo Crop [Image Only]", img.artCropImgOnly); break;
                        case 2: img.artCropDual = !img.artCropDual; img.setCrop(true); img.clear_rs_cache(); img.get_images(); window.SetProperty("SYSTEM.Photo Crop [Dual Mode]", img.artCropDual); break;
                        case 3: img.covCropImgOnly = !img.covCropImgOnly; img.setCrop(true); img.clear_rs_cache(); img.get_images(); window.SetProperty("SYSTEM.Cover Crop [Image Only]", img.covCropImgOnly); break;
                        case 4: img.covCropDual = !img.covCropDual; img.setCrop(true); img.clear_rs_cache(); img.get_images(); window.SetProperty("SYSTEM.Cover Crop [Dual Mode]", img.covCropDual); break;
                    }
                    break;
                case "Align":switch (i) {case 4: img.autoAlign = !img.autoAlign; p.sizes(); img.clear_rs_cache(); img.get_images(); window.SetProperty("SYSTEM.Image Align With Text", img.autoAlign); break; default: if (p.style == 0 || p.style == 2) {img.alignH = i - 1; window.SetProperty("SYSTEM.Image Alignment Horizontal", img.alignH);} else {img.alignV = i - 1; window.SetProperty("SYSTEM.Image Alignment Vertical", img.alignV);} img.clear_rs_cache(); img.get_images(); break;} break;
                case "AlignH": img.alignH = i - 1; window.SetProperty("SYSTEM.Image Alignment Horizontal", img.alignH); img.clear_rs_cache(); img.get_images(); break;
                case "AlignV": switch (i) {case 4: img.alignAuto = true; p.sizes(); img.clear_rs_cache(); img.get_images(); window.SetProperty("SYSTEM.Image Align Auto", img.alignAuto); break; default: img.alignV = i - 1; img.alignAuto = false; p.sizes(); img.clear_rs_cache(); img.get_images(); window.SetProperty("SYSTEM.Image Alignment Vertical", img.alignV); window.SetProperty("SYSTEM.Image Align Auto", img.alignAuto); break;} break;
                case "Reflection":switch (i) {case 1: img.reflection = !img.reflection;  img.setCrop(true); img.clear_rs_cache(); img.get_images(); window.SetProperty("SYSTEM.Image Reflection", img.reflection); break; default: img.reflectionType = i - 2;  img.setCrop(true); img.clear_rs_cache(); img.get_images(); window.SetProperty("SYSTEM.Image Reflection Type", img.reflectionType); break;} break;
                case "Border": switch (i) {case 1: img.border = img.border == 0 ? 1 : img.border == 1 ? 0 : img.border == 2 ? 3 : 2; window.SetProperty("SYSTEM.Image Border-1 Shadow-2 Both-3", img.border); img.create_images(); img.setCrop(true); img.clear_rs_cache(); img.get_images(); break; case 2: img.border = img.border == 0 ? 2 : img.border == 1 ? 3 : img.border == 2 ? 0 : 1; window.SetProperty("SYSTEM.Image Border-1 Shadow-2 Both-3", img.border); img.setCrop(true); img.clear_rs_cache(); img.get_images(); break;} break;
                case "Tags": if (i == 1 ) if (p.similar && p.similar < 5) tag.check(handles); else tag.write_tags(handles); break; case "Playlists": plman.ActivePlaylist = pl_menu[i].ix; break; case "Default": switch (i) {case 1: window.ShowProperties(); break; case 2: window.ShowConfigure(); break;}
            }
        } AlignMenu.Dispose(); AlignHMenu.Dispose(); AlignVMenu.Dispose(); BioMenu.Dispose(); BiogMenu.Dispose(); BiographyMenu.Dispose(); CovMenu.Dispose(); CropMenu.Dispose(); ImageMenu.Dispose(); HeadingMenu.Dispose(); LangMenu.Dispose(); LayoutMenu.Dispose(); LayoutBioMenu.Dispose(); LayoutRevMenu.Dispose(); menu.Dispose(); PasteMenu.Dispose(); PhotoMenu.Dispose(); ReflMenu.Dispose(); RevMenu.Dispose(); StylesEditorMenu.Dispose(); TagsMenu.Dispose(); ThemeMenu.Dispose(); TitleMenu.Dispose(); if (pl_show) {PlaylistsMenu.Dispose(); for (var j in pl_me) pl_me[j].Dispose();} this.right_up = false; return true;
    }
    
    this.button = function(x, y) {
        var menu = window.CreatePopupMenu(), WebMenu = window.CreatePopupMenu(), idx, Index = 1; Index = img.artistart ? this.MoreArtMenu(menu, Index) : this.MoreAlbMenu(menu, Index); menu.AppendMenuItem(MF_SEPARATOR, 0, 0); Index = this.WebTypeMenu(WebMenu, Index); WebMenu.AppendTo(menu, MF_STRING | MF_POPUP, "More...");
        var origArr = JSON.stringify(p.artists), origArrl = JSON.stringify(p.albums);
        idx = menu.TrackPopupMenu(x, y);
        if (idx >= 1 && idx <= Index) {
            var i = MenuMap[idx].value;
            switch (MenuMap[idx].type) {
                case "More-Artist":
                    switch (true) {
                        case i < p.artists.length + 1: if (origArr != JSON.stringify(p.artists) || i == 1 && !p.art_ix || p.art_ix == i - 1) break; p.art_ix = i - 1; img.get = false; t.get = 0; t.get_multi(false, p.art_ix, p.alb_ix); img.get_multi(p.art_ix); p.getData(false, p.focus, "multi_tag_jb", 0); break;
                        case i == p.artists.length + 2: this.counter = 0; this.cyc = !this.cyc; window.SetProperty("SYSTEM.Cycle Item", this.cyc); break;
                        case i == p.artists.length + 3: this.counter = 0; p.setCycItem(); break;
                    }
                    break;
                case "More-Album":
                    switch (true) {
                        case i < p.albums.length + 1: if (origArrl != JSON.stringify(p.albums) || i == 1 && !p.alb_ix || p.alb_ix == i - 1) break; p.alb_ix = i - 1; img.get = false; t.get = 0; t.get_multi(false, p.art_ix, p.alb_ix); img.get_multi(p.art_ix); p.getData(false, p.focus, "multi_tag_jb", 0); break;
                        case i == p.albums.length + 2: this.counter = 0; this.cyc = !this.cyc; window.SetProperty("SYSTEM.Cycle Item", this.cyc); break;
                        case i == p.albums.length + 3: this.counter = 0; p.setCycItem(); break;
                    }
                    break;
                case "Web": var artist = p.artists.length ? p.artists[0].name : name.artist(), brArr = ["", "/+similar", "/+albums"]; if (i < 4) ui.browser("https://" + "www.last.fm/" + (p.lfmLang == "en" ? "" : p.lfmLang + "/") + "music/" + encodeURIComponent(artist) + brArr[i - 1]); else ui.browser("https://www.allmusic.com/search/artists/" + encodeURIComponent(artist)); break;
        } menu.Dispose(); WebMenu.Dispose();}}

    this.wheel = function(step, auto, covOnly) {
        switch (true) {
            case img.artistart && !covOnly: if (!p.artistsUniq.length) break; for (var i = 0; i < p.artistsUniq.length; i++) if (!p.art_ix && name.artist() == p.artistsUniq[i].name || p.art_ix == p.artistsUniq[i].ix) break; i += step; if (i < 0) i = p.artistsUniq.length - 1; else if (i >= p.artistsUniq.length) i = 0; p.art_ix = p.artistsUniq[i].ix; break;
            case !img.artistart: if (!p.albumsUniq.length) break; for (var i = 0; i < p.albumsUniq.length; i++) if (!p.alb_ix && name.alb_artist() + " - " +  name.album() == p.albumsUniq[i].artist + " - " + p.albumsUniq[i].album || p.alb_ix == p.albumsUniq[i].ix) break; i += step; if (i < 0) i = p.albumsUniq.length - 1; else if (i >= p.albumsUniq.length) i = 0; p.alb_ix = p.albumsUniq[i].ix; break;
            default: return;
        } img.get = false; t.get_multi(false, p.art_ix, p.alb_ix); img.get_multi(p.art_ix); timer.reset(timer.zSearch, timer.zSearchi); timer.zSearch = window.SetTimeout(function() {p.getData(false, p.focus, "multi_tag_jb", 0); timer.zSearch = false;}, 1500); if (!auto) timer.men_step = Math.floor(fb.PlaybackTime);
    }
}
var men = new menu_object();

function text_manager() {
    var a_mod = "", a_mod_o = "", a_text = "", a_txt_done = false, albid = "", albid_o = "", alb_id = "", alb_id_o = "", alb_txt_arr = [], alb_txt_o = "", album = "", albumartist = "", art_txt_arr = [], art_txt_o = "", artist = "", artist_o = "", b_mod = "", b_mod_o = "", b_text = "", b_txt_done = false, bothBio_ix = -1, bothRev_ix = -1, calc = true, DT_LEFT = 0x00000000, DT_CENTER = 0x00000001, DT_VCENTER = 0x00000004, DT_WORDBREAK = 0x00000010, DT_SINGLELINE = 0x00000020, DT_CALCRECT = 0x00000400, DT_NOPREFIX = 0x00000800, DT_WORD_ELLIPSIS = 0x00040000, font_e = gdi.Font("Segoe UI", 15 * ui.scale, 1), imgText = p.imgText, init = true, l_mod = "", l_mod_o = "", l_text = "", l_txt_done = false, lc = StringFormat(0, 1), lfm_alb_done = false, lfm_alb_inf = "", lfm_alb_inf_o = "", lfm_alb_mod = "", lfm_alb_mod_o = "", new_text = false, szChkL = [], titleBio = 0, titleRev = 0, tState = false, update = 0;
    var allmusic_name = window.GetProperty(" Rating Text Name AllMusic", "Album rating"), lastfm_name = window.GetProperty(" Rating Text Name Last.fm", "Album rating"), ratingTextPos = window.GetProperty(" Rating Text Position Auto-0 Embed-1 Own Line-2", 0), score = window.GetProperty(" Statistics Show Last.fm Metacritic Score", true), stats = window.GetProperty(" Statistics Show Last.fm Scrobbles & Listeners", true);
    var amB1 = false, amB2 = false, amR1 = false, amR2 =false, lfmB1 = false, lfmB2 = false, lfmR1 =false, lfmR2 =false;
    var amBioLabel = window.GetProperty(" Heading Text Biography [AllMusic]", "$if2(%BIO_ARTIST% - Biography,Artist Unknown)"), amRevLabel = window.GetProperty(" Heading Text Review [AllMusic]", "$if2(%BIO_ALBUMARTIST%,Artist Unknown) - $if2(%BIO_ALBUM% - Album Review,Album Unknown)"), lfmBioLabel = window.GetProperty(" Heading Text Biography [Last.fm]", "$if2(%BIO_ARTIST% - Biography,Artist Unknown)"), lfmRevLabel = window.GetProperty(" Heading Text Review [Last.fm]", "$if2(%BIO_ALBUMARTIST%,Artist Unknown) - $if2(%BIO_ALBUM% - Album Review,Album Unknown)");
    var amBioTitle = window.GetProperty(" Title Biography [AllMusic]: Heading|No Heading", "AllMusic|AllMusic Biography").split("|"), amRevTitle = window.GetProperty(" Title Review [AllMusic]: Heading|No Heading", "AllMusic|AllMusic Review").split("|"), lfmBioTitle = window.GetProperty(" Title Biography [Last.fm]: Heading|No Heading", "Last.fm|Last.fm Biography").split("|"), lfmRevTitle = window.GetProperty(" Title Review [Last.fm]: Heading|No Heading", "Last.fm|Last.fm Review").split("|"), sp_w = []; this.title = window.GetProperty("SYSTEM.Title Hide-0 Auto-1 Show-2", 1); if (this.title > 2 || this.title < 0) this.title = 1; 
	var topTags = ["Tags", "Tags", "Tags", "Tags", "Tag", "タグ", "Tagi", "Tags", "Теги", "Taggar", "Etiketler", "标签"];
    this.alb_allmusic = true; this.avgRating = -1; this.bio_allmusic = false; this.alb_txt = ""; this.art_txt = ""; this.allmusic_alb = window.GetProperty("SYSTEM.Allmusic Alb", true); this.allmusic_bio = window.GetProperty("SYSTEM.Allmusic Bio", false); this.btnBioBoth = 0; this.btnRevBoth = 0; this.focus = true; this.get = 1; this.head = true; this.heading = ""; this.l = DT_LEFT | DT_NOPREFIX; this.cc = DT_CENTER | DT_VCENTER | DT_CALCRECT | DT_NOPREFIX | DT_WORD_ELLIPSIS; this.lc = DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_CALCRECT | DT_NOPREFIX | DT_WORD_ELLIPSIS; this.lockBio = window.GetProperty("SYSTEM.Lock Bio", false); this.lockRev = window.GetProperty("SYSTEM.Lock Rev", false); this.mulAlbum = false; this.mulArtist = false; this.na = ""; this.sbar_scroll = [0, 0, 0, 0]; this.text = ""; var lm = DT_LEFT | DT_CALCRECT | DT_WORDBREAK | DT_NOPREFIX;

    this.albumFlush = function() {this.text = false; b_mod = b_text = lfm_alb_inf = lfm_alb_mod = ""; b_mod_o = lfm_alb_inf_o = lfm_alb_mod_o = "1"; b_txt_done = lfm_alb_done = false; this.alb_txt = ""; this.head = false;}
    this.amBioPth = function() {var a = artist.clean(), stndBio = !p.art_ix || p.art_ix + 1 > p.artists.length, pth = stndBio ? p.cleanPth(p.amBioPth) : p.cleanMul(p.amBioMul, artist, "", "", 1), fn = pth + a + ".txt"; if (p.supCache && !p.file(pth)) pth = p.cleanMul(p.amBioSup, artist, "", "", 1); fn = pth + a + ".txt"; return [pth, fn, a ? true : false];}
    this.amRevPth = function() {var stndAlb = !p.alb_ix || p.alb_ix + 1 > p.albums.length, aa = stndAlb ? albumartist.clean() : artist.clean(), l = album.clean(), pth = stndAlb ? p.cleanPth(p.amRevPth) : p.cleanMul(p.amRevMul, artist, album, "", 0), fn = pth + aa + " - " + l + ".txt"; if (!stndAlb && p.supCache && !p.file(pth)) pth = p.cleanMul(p.amRevSup, artist, album, "", 0); fn = pth + aa + " - " + l + ".txt"; return [pth, fn, aa && l ? true : false];}
    this.artistFlush = function() {this.text = false; a_txt_done = l_txt_done = false; a_mod = a_text = l_mod = l_text = ""; a_mod_o = l_mod_o = "1"; this.art_txt = ""; this.head = false;}
    this.album_reset = function(upd) {alb_id_o = alb_id; alb_id = !p.eval("[%album%]") ? p.eval("%album artist%%path%") : p.eval("%album artist%%album%"); var new_album = alb_id != alb_id_o; if (new_album || upd) {album = name.album(); albumartist = name.alb_artist(); this.albumFlush(); this.mulAlbum = false;}}
    this.artist_reset = function(upd) {if (p.artistsSame()) return; artist_o = artist; artist = name.artist(); var new_artist = artist != artist_o; if (new_artist || upd) {this.mulArtist = false; this.artistFlush();}}
    this.get_multi = function(p_calc, n1, n2) {if (p.img_only) return; switch (true) {case img.artistart: artist_o = artist; artist = n1 < p.artists.length ? p.artists[n1].name : name.artist(); var new_artist = artist != artist_o; if (new_artist) {this.artistFlush(); p.art_ix = n1; this.mulArtist = true;} this.grab_text(p_calc); this.get = 0; break; case !img.artistart: albid_o = albid; artist = n2 < p.albums.length ? p.albums[n2].artist : name.alb_artist(); var alb = n2 < p.albums.length ? p.albums[n2].album : name.album(); albid = artist + alb; var new_album = albid != albid_o; if (new_album) {album = alb; albumartist = artist; this.albumFlush(); this.mulAlbum = true;} this.grab_text(p_calc); this.get = 0; break;}}
    this.halt = function() {return p.w <= 10 || p.h <= 10;}
    this.block = function() {return this.halt() || !window.IsVisible;}
    var editText = function() {return p.text_only ? "Type: Text Only" : (p.img_only ? "Type: Image Only" : "Name: " + p.style_arr[p.style] + (p.style < 4 ? "\nType: Auto\nAdjust: Ctrl" : "\nType: Freestyle\n - Adjust: Ctrl, Ctrl + Alt (Image) or Ctrl + Shift (Text)\n - Overlay Strength: Shift + Wheel Over Text"));}
    this.get_txt_fallback = function() {if (this.scrollbar_type().draw_timer) return; if (!p.multi_new() && !update) return; if (!this.get) return; this.album_reset(update); this.artist_reset(update); this.na = ""; if (update) init = true; update = 0; if (calc) calc = img.artistart ? 1 : 2; this.grab_text(calc); if (init) {img.get_images(); init = false;} if (this.get == 2) p.item_changed(p.focus, 1000); calc = false; this.get = 0;}
    this.get_widths = function() {try {var g = gdi.CreateImage(1, 1), gb = g.GetGraphics(), sp_arr = ["  ", amBioTitle[0] + "  ", lfmBioTitle[0] + "  ", amRevTitle[0] + "  ", lfmRevTitle[0] + "  ", amBioTitle[1] + "  ", lfmBioTitle[1] + "  ", amRevTitle[1] + "  ", lfmRevTitle[1] + "  "]; for (var i = 0; i < 9; i++) sp_w[i] = Math.max(gb.CalcTextWidth(sp_arr[i], ui.fontT), 1); g.ReleaseGraphics(gb); g.Dispose();} catch (e) {}}
    this.grab = function() {update = 1; if (this.block()) return this.get = 1; this.grab_text(false); img.grab_a_img(); img.grab_f_img(); update = 0; a_txt_done = l_txt_done = b_txt_done = lfm_alb_done = false;}
    this.j_draw = function(gr) {if (ui.heading || !this.na) return; try {var j_x = Math.round(p.text_w / 2) + p.text_l, j_h = Math.round(ui.font_h * 1.5), j_y = p.text_t + (p.lines_drawn * ui.font_h - j_h) / 3, rs1 = Math.min(5, j_h / 2), rs2 = Math.min(4, (j_h - 2) / 2); gr.SetSmoothingMode(4); var j_w = gr.CalcTextWidth(this.na, ui.j_font) + 25; gr.FillRoundRect(j_x - j_w / 2, j_y, j_w, j_h, rs1, rs1, 0xDB000000); gr.DrawRoundRect(j_x - j_w / 2, j_y, j_w, j_h, rs1, rs1, 1, 0x64000000); gr.DrawRoundRect(j_x - j_w / 2 + 1, j_y + 1, j_w - 2, j_h - 2, rs2, rs2, 1, 0x28ffffff); gr.GdiDrawText(this.na, ui.j_font, RGB(0, 0, 0), j_x - j_w / 2 + 1, j_y + 1 , j_w, j_h, t.cc); gr.GdiDrawText(this.na, ui.j_font, 0xffff4646, j_x - j_w / 2, j_y, j_w, j_h, t.cc);} catch(e) {}}
    this.lfmBioPth = function() {var a = artist.clean(), stndBio = !p.art_ix || p.art_ix + 1 > p.artists.length, pth = stndBio ? p.cleanPth(p.lfmBioPth) : p.cleanMul(p.lfmBioMul, artist, "", "", 1), fn = pth + a + ".txt"; if (!stndBio && p.supCache && !p.file(fn)) pth = p.cleanMul(p.lfmBioSup, artist, "", "", 1); fn = pth + a + ".txt"; return [pth, fn, a ? true : false];}
    this.lfmRevPth = function() {var stndAlb = !p.alb_ix || p.alb_ix + 1 > p.albums.length, aa = stndAlb ? albumartist.clean() : artist.clean(), l = album.clean(), pth = stndAlb ? p.cleanPth(p.lfmRevPth) : p.cleanMul(p.lfmRevMul, artist, album, "", 0), fn = pth + aa + " - " + l + ".txt"; if (!stndAlb && p.supCache && !p.file(fn)) pth = p.cleanMul(p.lfmRevSup, artist, album, "", 0); fn = pth + aa + " - " + l + ".txt"; return [pth, fn, aa && l ? true : false];}
    this.on_playback_new_track = function() {if (!p.multi_new()) return; if (this.block()) {this.get = 1; p.get_multi(true); this.album_reset(); this.artist_reset();} else {p.get_multi(true); this.album_reset(); this.artist_reset(); this.na = ""; this.grab_text(false); this.get = 0;}}
    this.on_size = function() {this.grab_text(false); p.get_multi(true); but.refresh();}
    this.rating = -1; this.l_rating = -1; this.rp = true; this.paint = function() {if (this.rp) window.Repaint();}
    this.scrollbar_type = function() {return img.artistart ? art_scrollbar : alb_scrollbar;}
    var tf = function(n) {
        try {var a = (img.artistart ? artist : (p.alb_ix ? albumartist : artist)).escape(), aa = (img.artistart ? (p.art_ix ? artist : albumartist) : albumartist).escape(), l = album.replace("Album Unknown", "").escape();
        var stnd = img.artistart && !p.art_ix || !img.artistart && !p.alb_ix; n = n.replace(/%more_item%/gi, !stnd ? "$&#@!%path%#@!" : "$&");
        n = n.replace(/((\$if|\$and|\$or|\$not|\$xor)(|\d)\(|\[)[^$%]*%bio_artist%/gi, a ? "$&#@!%path%#@!" : "$&").replace(/%bio_artist%/gi, a).replace(/((\$if|\$and|\$or|\$not|\$xor)(|\d)\(|\[)[^$%]*%bio_albumartist%/gi, aa ? "$&#@!%path%#@!" : "$&").replace(/%bio_albumartist%/gi, aa).replace(/((\$if|\$and|\$or|\$not|\$xor)(|\d)\(|\[)[^$%]*%bio_album%/gi, l ? "$&#@!%path%#@!" : "$&").replace(/%bio_album%/gi, l);
        n = p.eval(n); n = n.replace(/#@!.*?#@!/g, "");} catch (e) {return img.artistart ? (artist + (artist ? " - Biography" : "Artist Unknown")) : (albumartist ? albumartist : "Artist Unknown") + " - " + (album ? album + " - Album Review" : "Album Unknown");}
        return n;}

    this.grab_text = function(p_calc) {
        if (p.img_only) return; var a = artist.clean(); new_text = false;
        switch (true) {
            case img.artistart:
                imgText = !this.mulArtist ? p.imgText : true; if (ui.heading) this.heading = ui.headText ? tf(this.allmusic_bio ? amBioLabel : lfmBioLabel) : ""; if (!a) break;
                if (ui.bothBio) {if (!a_txt_done || update) {a_txt_done = true; this.text_a(a); if (!l_txt_done || update) {l_txt_done = true; this.text_l(a);}} break;}
                if (!this.allmusic_bio && (!l_txt_done || update)) {l_txt_done = true; this.text_l(a); if (!l_text && !this.lockBio && (!a_txt_done || update)) {a_txt_done = true; this.text_a(a);}}
                if (this.allmusic_bio && (!a_txt_done || update)) {a_txt_done = true; this.text_a(a); if (!a_text && !this.lockBio && (!l_txt_done || update)) {l_txt_done = true; this.text_l(a);}}
                break;
            case !img.artistart:
                imgText = !this.mulAlbum ? p.imgText : true; if (!imgText) szChkL[p.alb_ix] = imgText;
                var aa = albumartist.clean(), l = album.clean(); if (ui.heading) this.heading = ui.headText ? tf(this.allmusic_alb ? amRevLabel : lfmRevLabel) : "";
                if (!aa || !l) {this.rating = -1; this.l_rating = -1; this.avgRating = -1; if (!p.text_only && !this.mulAlbum && tState != this.text) {img.clear_c_rs_cache(); tState == this.text;} but.refresh(); break;}
                if (p.ir() && !p.alb_ix && (!p.focus || p.ir_focus())) break;
                if (ui.bothRev) {if (!b_txt_done || update) {b_txt_done = true; this.text_b(a, aa, l); if (!lfm_alb_done || update) {lfm_alb_done = true; this.lfm_alb(a, aa, l);}} break;}
                if (this.allmusic_alb && (!b_txt_done || update)) {b_txt_done = true; this.text_b(a, aa, l); if (!b_text && !this.lockRev && (!lfm_alb_done || update)) {lfm_alb_done = true; this.lfm_alb(a, aa, l);}}
                if (!this.allmusic_alb && (!lfm_alb_done || update)) {lfm_alb_done = true; this.lfm_alb(a, aa, l); if (!lfm_alb_inf && !this.lockRev && (!b_txt_done || update)) {b_txt_done = true; this.text_b(a, aa, l);}}
                break;
        }
        if (!update || new_text) {
            this.alb_txt = ""; amB1 = false; amB2 = false; amR1 = false; amR2 = false; this.art_txt = ""; this.head = true; lfmB1 = false; lfmB2 = false; lfmR1 = false; lfmR2 = false;
            switch (true) {
                case !ui.bothBio:
                    if (this.allmusic_bio) {if (this.title == 2 && !b_text && lfm_alb_inf) lfm_alb_inf = lfm_alb_inf.replace(/Last.fm: /g, ""); 
                    this.art_txt = !this.lockBio ? a_text ? (this.title == 2 ? amBioTitle[ui.heading ? 0 : 1] + "\r\n" : "") + a_text : (this.title == 2 && l_text ? lfmBioTitle[ui.heading ? 0 : 1] + "\r\n" : "") + l_text : (this.title == 2 && (a_text || imgText || p.text_only) ? amBioTitle[ui.heading ? 0 : 1] + "\r\n" + (a_text ? "" : "Nothing Found") : "") + a_text; if (a_text || this.lockBio) amB1 = true; else if (l_text) lfmB1 = true; if (a_text || this.lockBio) this.bio_allmusic = true; else if (l_text) this.bio_allmusic = false; else this.bio_allmusic = true;}
                    else {if (this.title == 2 && l_text) l_text = l_text.replace(/Last.fm: /g, ""); this.art_txt = !this.lockBio ? l_text ? (this.title == 2 ? lfmBioTitle[ui.heading ? 0 : 1] + "\r\n" : "") + l_text : (this.title == 2 && a_text ? amBioTitle[ui.heading ? 0 : 1] + "\r\n" : "") + a_text : (this.title == 2 && (l_text || imgText || p.text_only) ? lfmBioTitle[ui.heading ? 0 : 1] + "\r\n" + (l_text ? "" : "Nothing Found") : "") + l_text; if (l_text || this.lockBio) lfmB1 = true; else if (a_text) amB1 = true; if (l_text || this.lockBio) this.bio_allmusic = false; else if (a_text) this.bio_allmusic = true; else this.bio_allmusic = false;} this.btnBioBoth = false; break;
                case ui.bothBio:
                    if (this.allmusic_bio) {if (a_text) {this.art_txt = (this.title ? amBioTitle[ui.heading ? 0 : 1] + "\r\n" : "") + a_text; amB1 = true;} if (l_text) {l_text = l_text.replace(/Last.fm: /g, ""); this.art_txt = this.art_txt + (a_text ? "\r\n\r\n" : "") + (this.title ? "#!#" + lfmBioTitle[ui.heading ? 0 : 1] + "\r\n" : "") + l_text; lfmB2 = true;} if (a_text) this.bio_allmusic = true; else if (l_text) this.bio_allmusic = false; else this.bio_allmusic = true;}
                    else {if (l_text) {l_text = l_text.replace(/Last.fm: /g, ""); this.art_txt = (this.title ? lfmBioTitle[ui.heading ? 0 : 1] + "\r\n" : "") + l_text; lfmB1 = true;} if (a_text) {this.art_txt = this.art_txt + (l_text ? "\r\n\r\n" : "") + (this.title ? "#!#" + amBioTitle[ui.heading ? 0 : 1] + "\r\n" : "") + a_text; amB2 = true;} if (l_text) this.bio_allmusic = false; else if (a_text) this.bio_allmusic = true; else this.bio_allmusic = false;}
                    this.btnBioBoth = a_text && l_text || !a_text && !l_text ? true : false; break;
            }
            switch (true) {
                case !ui.bothRev:
                    if (this.allmusic_alb) {if (this.title == 2 && !b_text && lfm_alb_inf) lfm_alb_inf = lfm_alb_inf.replace(/Last.fm: /g, ""); this.alb_txt = !this.lockRev ? b_text ? (this.title == 2 ? amRevTitle[ui.heading ? 0 : 1] + "\r\n" : "") + b_text : (this.title == 2 && lfm_alb_inf ? lfmRevTitle[ui.heading ? 0 : 1] + "\r\n" : "") + lfm_alb_inf : (this.title == 2 && (b_text || imgText || p.text_only) ? amRevTitle[ui.heading ? 0 : 1] + "\r\n" + (b_text ? "" : "Nothing Found") : "") + b_text; if (b_text || this.lockRev) amR1 = true; else if (lfm_alb_inf) lfmR1 = true; if (b_text || this.lockRev) this.alb_allmusic = true; else if (lfm_alb_inf) this.alb_allmusic = false; else this.alb_allmusic = true;}
                    else {if (this.title == 2 && lfm_alb_inf) lfm_alb_inf = lfm_alb_inf.replace(/Last.fm: /g, ""); this.alb_txt = !this.lockRev ? lfm_alb_inf ? (this.title == 2 ? lfmRevTitle[ui.heading ? 0 : 1] + "\r\n" : "") + lfm_alb_inf : (this.title == 2 && b_text ? amRevTitle[ui.heading ? 0 : 1] + "\r\n" : "") + b_text : (this.title == 2 && (lfm_alb_inf || imgText || p.text_only) ? lfmRevTitle[ui.heading ? 0 : 1] + "\r\n" + (lfm_alb_inf ? "" : "Nothing Found") : "") + lfm_alb_inf; if (lfm_alb_inf || this.lockRev) lfmR1 = true; else if (b_text) amR1 = true; if (lfm_alb_inf || this.lockRev) this.alb_allmusic = false; else if (b_text) this.alb_allmusic = true; else this.alb_allmusic = false;} this.btnRevBoth = false; break;
                case ui.bothRev:
                    if (this.allmusic_alb) {if (b_text) {this.alb_txt = (this.title ? amRevTitle[ui.heading ? 0 : 1] + "\r\n" : "") + b_text; amR1 = true;} if (lfm_alb_inf) {lfm_alb_inf = lfm_alb_inf.replace(/Last.fm: /g, ""); this.alb_txt = this.alb_txt + (b_text ? "\r\n\r\n" : "") + (this.title ? "#!#" + lfmRevTitle[ui.heading ? 0 : 1] + "\r\n" : "") + lfm_alb_inf; lfmR2 = true;} if (b_text) this.alb_allmusic = true; else if (lfm_alb_inf) this.alb_allmusic = false; else this.alb_allmusic = true;}
                    else {if (lfm_alb_inf) {lfm_alb_inf = lfm_alb_inf.replace(/Last.fm: /g, ""); this.alb_txt = (this.title ? lfmRevTitle[ui.heading ? 0 : 1] + "\r\n" : "") + lfm_alb_inf; lfmR1 = true;} if (b_text) {this.alb_txt = this.alb_txt + (lfm_alb_inf ? "\r\n\r\n" : "") + (this.title ? "#!#" + amRevTitle[ui.heading ? 0 : 1] + "\r\n" : "") + b_text; amR2 = true;} if (lfm_alb_inf) this.alb_allmusic = false; else if (b_text) this.alb_allmusic = true; else this.alb_allmusic = false;}
                    this.btnRevBoth = b_text && lfm_alb_inf || !b_text && !lfm_alb_inf ? true : false; break;
            }
            titleBio = !this.title || !this.art_txt || !ui.bothBio && this.title != 2 ? 0 : 1; titleRev = !this.title || !this.alb_txt || !ui.bothRev && this.title != 2 ? 0 : 1;
            if (ui.stars == 1 && ui.src && this.btnRevBoth) {var c = 0; this.avgRating = -1; if (this.rating != -1 || this.l_rating != -1) {this.avgRating = 0; if (this.rating != -1) {this.avgRating += this.rating; c++;} if (this.l_rating != -1) {this.avgRating += this.l_rating; c++;} this.avgRating /= c; this.avgRating = Math.round(this.avgRating);}}
            if (!imgText) this.text = img.artistart ? this.art_txt ? true : false : this.alb_txt ? true : false; else this.text = true; img.setCrop(true);
            if (!p.imgText && this.mulAlbum && !szChkL[p.alb_ix] && !this.alb_txt) {szChkL[p.alb_ix] = true; img.clear_c_rs_cache();}
            if (!this.art_txt && (p.text_only || imgText)) this.art_txt = !ui.heading ? "There is no artist biography to display" : "Nothing Found";
            if (!this.alb_txt && (p.text_only || imgText)) this.alb_txt = !ui.heading ? "There is no album review to display" : "Nothing Found";
            if ((img.artistart && !this.art_txt || !img.artistart && !this.alb_txt) && !p.text_only) this.head = false;
            if (this.art_txt != art_txt_o || p_calc && p_calc !== 2) {this.art_calc(); art_txt_o = this.art_txt;}
            if (this.alb_txt != alb_txt_o || p_calc && p_calc !== 1) {this.alb_calc(); alb_txt_o = this.alb_txt;}
            if (!p.text_only && !this.mulAlbum && tState != this.text) {img.clear_c_rs_cache();} tState = this.text;
            if (p.text_only && !ui.blur) this.paint();
        }
        new_text = false;
    }

    this.alb_calc = function() {
        if (!this.alb_txt || p.img_only) return;
        var ctt = 0, g = gdi.CreateImage(1, 1), gb = g.GetGraphics(), l = gb.EstimateLineWrap(this.alb_txt, ui.font, p.text_w).toArray(); alb_txt_arr = []; bothRev_ix = -1;
        for (var i = 0; i < l.length; i += 2) {if (!titleRev) alb_txt_arr.push(l[i].trim()); else {if (l[i].indexOf("#!#") != -1) {bothRev_ix = ctt; l[i] = l[i].replace("#!#", "");} !i || ctt == bothRev_ix ? alb_txt_arr.push(l[i]) : alb_txt_arr.push(l[i].trim()); ctt++;}}
        but.refresh(true); alb_scrollbar.reset(); alb_scrollbar.metrics(p.sbar_x, p.sbar_y, ui.scr_w, p.sbar_h, p.lines_drawn, ui.font_h); alb_scrollbar.set_rows(alb_txt_arr.length); g.ReleaseGraphics(gb); g.Dispose();
    }

    this.art_calc = function() {
        if (!this.art_txt || p.img_only) return;
        var ctt = 0, g = gdi.CreateImage(1, 1), gb = g.GetGraphics(), l = gb.EstimateLineWrap(this.art_txt, ui.font, p.text_w).toArray(); art_txt_arr = []; bothBio_ix = -1;
        for (var i = 0; i < l.length; i += 2) {if (!titleBio) art_txt_arr.push(l[i].trim()); else {if (l[i].indexOf("#!#") != -1) {bothBio_ix = ctt; l[i] = l[i].replace("#!#", "");} !i || ctt == bothBio_ix ? art_txt_arr.push(l[i]) : art_txt_arr.push(l[i].trim()); ctt++;}}
        but.refresh(true); art_scrollbar.reset(); art_scrollbar.metrics(p.sbar_x, p.sbar_y, ui.scr_w, p.sbar_h, p.lines_drawn, ui.font_h); art_scrollbar.set_rows(art_txt_arr.length); g.ReleaseGraphics(gb); g.Dispose();
    }

    this.text_l = function(a) {
        var stndBio = !p.art_ix || p.art_ix + 1 > p.artists.length, lfm_a = (stndBio ? p.cleanPth(p.lfmBioPth) : p.cleanMul(p.lfmBioMul, artist, "", "", 1)) + a + ".txt";
        if (!stndBio && p.supCache && !p.file(lfm_a)) lfm_a = p.cleanMul(p.lfmBioSup, artist, "", "", 1) + a + ".txt";
        if (!p.file(lfm_a)) return; l_mod = p.last_modified(lfm_a); if (!(l_mod - l_mod_o)) return; l_text = utils.ReadTextFile(lfm_a).trim(); if (!stats) {var f = l_text.indexOf("Last.fm: "); if (f != -1) l_text = l_text.slice(0, f).trim();}
		if (p.lfmLang_ix > 3) l_text = l_text.replace("Top Tags: ", topTags[p.lfmLang_ix] + ": ");
        new_text = true; l_mod_o = l_mod; if (!p.text_only) img.clear_a_rs_cache(); this.sbar_scroll[0] = 0;
    }

    this.text_a = function(a) {
        var stndBio = !p.art_ix || p.art_ix + 1 > p.artists.length, am_a = (stndBio ? p.cleanPth(p.amBioPth) : p.cleanMul(p.amBioMul, artist, "", "", 1)) + a + ".txt";
        if (p.supCache && !p.file(am_a)) am_a = p.cleanMul(p.amBioSup, artist, "", "", 1) + a + ".txt";
        if (!p.file(am_a)) return; a_mod = p.last_modified(am_a); if (!(a_mod - a_mod_o)) return; a_text = utils.ReadTextFile(am_a).trim(); new_text = true; a_mod_o = a_mod;
        if (!p.text_only) img.clear_a_rs_cache(); this.sbar_scroll[1] = 0;
    }
    
    this.text_b = function(a, aa, l) {
        if (!p.alb_ix || p.alb_ix + 1 > p.albums.length) var am_b = p.cleanPth(p.amRevPth) + aa + " - " + l + ".txt";
        else {var am_b = p.cleanMul(p.amRevMul, artist, album, "", 0) + a + " - " + l + ".txt"; if (p.supCache && !p.file(am_b)) am_b = p.cleanMul(p.amRevSup, artist, album, "", 0) + a + " - " + l + ".txt";}
        if (!p.file(am_b)) {this.rating = -1; but.refresh(); return;} b_mod = p.last_modified(am_b); if (!(b_mod - b_mod_o)) return; b_text = utils.ReadTextFile(am_b).trim(); new_text = true; b_mod_o = b_mod; this.rating = -1;
        var s = b_text.indexOf(">> Album rating: ") + 17, f = b_text.indexOf(" <<"), titleOn = ui.bothRev && this.title || this.title == 2;
        if (ui.a_rating) {if (s !=-1 && f != -1 && f > s) this.rating = b_text.substring(s, f); if (!isNaN(this.rating) && this.rating != 0 && this.rating != -1) this.rating *= 2; else this.rating = -1;}
        if ((ui.stars == 1 && ui.src || !ui.a_rating) && f != -1) b_text = b_text.substring(f + 5);
        else if ((ui.stars == 2 || ui.stars == 1 && !ui.src) && (ratingTextPos == 2 || titleOn && !ratingTextPos) && this.rating != -1) {b_text = (!titleOn ? allmusic_name + ":\r\n\r\n" : "") + b_text.substring(f + 5)}
        else {if (!ui.stars || this.rating == -1) {var s = b_text.indexOf(" <<"); if (s != -1) b_text = b_text.slice(s + 3);} else if (allmusic_name != "Album rating") b_text = b_text.replace("Album rating", allmusic_name);}
        if (!b_text) but.refresh(); if (!p.text_only &&!this.mulAlbum) img.clear_c_rs_cache(); this.sbar_scroll[3] = 0;
    }
    
    this.lfm_alb = function(a, aa, l) {
        if (!p.alb_ix || p.alb_ix + 1 > p.albums.length) var lfm_b = p.cleanPth(p.lfmRevPth) + aa + " - " + l + ".txt";
        else {var lfm_b = p.cleanMul(p.lfmRevMul, artist, album, "", 0) + a + " - " + l + ".txt"; if (p.supCache && !p.file(lfm_b)) lfm_b = p.cleanMul(p.lfmRevSup, artist, album, "", 0) + a + " - " + l + ".txt";}
        if (!p.file(lfm_b)) {this.l_rating = -1; but.refresh(); return;} 
        lfm_alb_mod = p.last_modified(lfm_b); if (!(lfm_alb_mod - lfm_alb_mod_o)) return; lfm_alb_inf = utils.ReadTextFile(lfm_b).trim();
        new_text = true; lfm_alb_mod_o = lfm_alb_mod; this.l_rating = -1;
        if (ui.l_rating) {var s = lfm_alb_inf.indexOf("Rating: "); if (s != -1) {this.l_rating = lfm_alb_inf.substring(s).replace(/\D/g, ""); this.l_rating = Math.min(((Math.floor(0.1111 * this.l_rating + 0.3333) / 2)), 5); if (ui.stars == 1 && ui.src) this.l_rating *= 2; if ((ui.stars == 2 || ui.stars == 1 && !ui.src) && this.l_rating != -1) {var titleOn = ui.bothRev && this.title || this.title == 2; if (ratingTextPos == 2 || titleOn && !ratingTextPos) {this.l_rating *= 2; lfm_alb_inf = (!titleOn ? lastfm_name + ":\r\n\r\n" : "") + lfm_alb_inf} else lfm_alb_inf = ">> " + lastfm_name + ": " + this.l_rating + " <<  " + ((/^Top Tags: /).test(lfm_alb_inf) ? "\r\n\r\n" : "") + lfm_alb_inf;}}}
        if (!stats) {lfm_alb_inf = lfm_alb_inf.replace(/^Last.fm: .*$(\r\n\r\n)?/m, "");}
        lfm_alb_inf = score ? lfm_alb_inf.replace("Rating: ", "") : lfm_alb_inf.replace(/^Rating: .*$/m, "").trim();
		if (p.lfmLang_ix > 3) lfm_alb_inf = lfm_alb_inf.replace("Top Tags: ", topTags[p.lfmLang_ix] + ": ");
        if (!lfm_alb_inf) but.refresh(); if (!p.text_only &&!this.mulAlbum) img.clear_c_rs_cache(); this.sbar_scroll[2] = 0;
    }

    this.draw = function(gr) {try {
        if (!p.img_only || p.text_only) {
            this.get_txt_fallback();
            if (ui.overlayStyle && p.style > 3 && this.text && !p.text_only) {gr.SetSmoothingMode(2);
                switch (ui.overlayStyle) {
                    case 1: gr.FillSolidRect(p.tBoxL, p.tBoxT, p.tBoxW, p.tBoxH, !ui.blur_dark && !ui.blur_light ? ui.rndRectCol : ui.blurOvCol); break;
                    case 2: var o = Math.round(ui.arc_w / 2); gr.FillSolidRect(p.tBoxL + o, p.tBoxT + o, p.tBoxW - o * 2, p.tBoxH - o * 2, !ui.blur_dark && !ui.blur_light ? ui.rndRectCol : ui.blurOvCol); gr.DrawRect(p.tBoxL + o, p.tBoxT + o, p.tBoxW - ui.arc_w - 1, p.tBoxH - ui.arc_w - 1, ui.arc_w, ui.rndRectBorCol); break;
                    case 3: gr.FillRoundRect(p.tBoxL, p.tBoxT, p.tBoxW, p.tBoxH, p.arc, p.arc, !ui.blur_dark && !ui.blur_light ? ui.rndRectCol : ui.blurOvCol); break;
                    case 4: var o = Math.round(ui.arc_w / 2); gr.FillRoundRect(p.tBoxL + o, p.tBoxT + o, p.tBoxW - o * 2, p.tBoxH - o * 2, p.arc, p.arc, 
                    !ui.blur_dark && !ui.blur_light ? ui.rndRectCol : ui.blurOvCol); gr.DrawRoundRect(p.tBoxL + o, p.tBoxT + o, p.tBoxW - ui.arc_w - 1, p.tBoxH - ui.arc_w - 1, p.arc, p.arc, ui.arc_w, ui.rndRectBorCol); break;
                }
            }
            if (img.artistart && this.art_txt) {
                var s = Math.round(art_scrollbar.delta / ui.font_h + 0.4), f = s + p.lines_drawn; f = art_txt_arr.length < f ? art_txt_arr.length : f;
                for (var i = s; i < f; i++) {var item_y = ui.font_h * i + p.text_t - art_scrollbar.delta; 
                    if (!ui.heading && titleBio) {var iy = Math.round(item_y + ui.font_h / 2);
                        if (!i && amB1) gr.DrawLine(p.text_l + sp_w[5], iy, p.text_l + p.text_w, iy, 1, ui.titlelinecol);
                        if (!i && lfmB1) gr.DrawLine(p.text_l + sp_w[6], iy, p.text_l + p.text_w, iy, 1, ui.titlelinecol);
                        if (i == bothBio_ix && amB2) gr.DrawLine(p.text_l + sp_w[5], iy, p.text_l + p.text_w, iy, 1, ui.titlelinecol);
                        if (i == bothBio_ix && lfmB2) gr.DrawLine(p.text_l + sp_w[6], iy, p.text_l + p.text_w, iy, 1, ui.titlelinecol);
                }
                if (titleBio && (!i || i == bothBio_ix)) gr.GdiDrawText(art_txt_arr[i], ui.fontT, ui.titlecol, p.text_l, item_y, p.text_w, ui.font_h, this.l);
                else gr.GdiDrawText(art_txt_arr[i], ui.font, ui.textcol, p.text_l, item_y, p.text_w, ui.font_h, this.l);} if (ui.scrollbar_show) art_scrollbar.draw(gr);
            }
            if (!img.artistart && this.alb_txt) {
                var s = Math.round(alb_scrollbar.delta / ui.font_h + 0.4), f = s + p.lines_drawn; f = alb_txt_arr.length < f ? alb_txt_arr.length : f;
                var r = (ui.stars == 2 || ui.stars == 1 && !ui.src) && (ratingTextPos == 2 || titleRev && !ratingTextPos) && !img.artistart && alb_txt_arr.length > 1 && (!titleRev ? (this.alb_allmusic && this.rating != -1 || !this.alb_allmusic && this.l_rating != -1) : true);
                var amW1 = sp_w[ui.heading ? 3 : 7], amW2 = sp_w[ui.heading ? 3 : 7], lfmW1 = sp_w[ui.heading ? 4 : 8], lfmW2 = sp_w[ui.heading ? 4 : 8];
                for (var i = s; i < f; i++) {var item_y = ui.font_h * i + p.text_t - alb_scrollbar.delta;
                    if (r) switch (titleRev) {
                        case 0: var rating = this.alb_allmusic ? this.rating : this.l_rating; if (i == 0 && rating >= 0) gr.DrawImage(but.ratingImages[rating], p.text_l + gr.CalcTextWidth((this.alb_allmusic ? allmusic_name : lastfm_name) + ":  ", ui.font), item_y + Math.round((ui.font_h - but.r_h1 / 2) / 1.8), but.r_w1 / 2, but.r_h1 / 2, 0, 0, but.r_w1, but.r_h1, 0, 255); break;
                        case 1:
                            if (!i && amR1 && this.rating >= 0) {amW1 += (sp_w[0] + but.r_w2); gr.DrawImage(but.ratingImages[this.rating], p.text_l + sp_w[ui.heading ? 3 : 7], item_y + Math.round((ui.font_h - but.r_h1 / 2) / 1.8), but.r_w1 / 2, but.r_h1 / 2, 0, 0, but.r_w1, but.r_h1, 0, 255);}
                            if (!i && lfmR1 && this.l_rating >= 0) {lfmW1 += (sp_w[0] + but.r_w2); gr.DrawImage(but.ratingImages[this.l_rating], p.text_l + sp_w[ui.heading ? 4 : 8], item_y + Math.round((ui.font_h - but.r_h1 / 2) / 1.8), but.r_w1 / 2, but.r_h1 / 2, 0, 0, but.r_w1, but.r_h1, 0, 255);}
                            if (i == bothRev_ix && amR2 && this.rating >= 0) {amW2 += (sp_w[0] + but.r_w2); gr.DrawImage(but.ratingImages[this.rating], p.text_l + sp_w[ui.heading ? 3 : 7], item_y + Math.round((ui.font_h - but.r_h1 / 2) / 1.8), but.r_w1 / 2, but.r_h1 / 2, 0, 0, but.r_w1, but.r_h1, 0, 255);}
                            if (i == bothRev_ix && lfmR2 && this.l_rating >= 0) {lfmW2 += (sp_w[0] + but.r_w2); gr.DrawImage(but.ratingImages[this.l_rating], p.text_l + sp_w[ui.heading ? 4 : 8], item_y + Math.round((ui.font_h - but.r_h1 / 2) / 1.8), but.r_w1 / 2, but.r_h1 / 2, 0, 0, but.r_w1, but.r_h1, 0, 255);}
                            break;
                    }
                    if (!ui.heading && titleRev) {var iy = Math.round(item_y + ui.font_h / 2);
                        if (!i && amR1) gr.DrawLine(p.text_l + amW1, iy, p.text_l + p.text_w, iy, 1, ui.titlelinecol);
                        if (!i && lfmR1) gr.DrawLine(p.text_l + lfmW1, iy, p.text_l + p.text_w, iy, 1, ui.titlelinecol);
                        if (i == bothRev_ix && amR2) gr.DrawLine(p.text_l + amW2, iy, p.text_l + p.text_w, iy, 1, ui.titlelinecol);
                        if (i == bothRev_ix && lfmR2) gr.DrawLine(p.text_l + lfmW2, iy, p.text_l + p.text_w, iy, 1, ui.titlelinecol);
                    }
                    if (titleRev && (!i || i == bothRev_ix)) gr.GdiDrawText(alb_txt_arr[i], ui.fontT, ui.titlecol, p.text_l, item_y, p.text_w, ui.font_h, this.l);
                    else gr.GdiDrawText(alb_txt_arr[i], ui.font, ui.textcol, p.text_l, item_y, p.text_w, ui.font_h, this.l);
                } if (ui.scrollbar_show) alb_scrollbar.draw(gr);}
        }} catch (e) {}
    }

    this.drawEd = function(gr) {try {
        if (utils.IsKeyPressed(0x11) && this.focus && p.m_y != -1|| p.newStyle) {
            var ed = gr.MeasureString(editText(), font_e, 15, 15, p.w - 15, p.h - 15, lc);
            gr.FillSolidRect(10, 10, ed.Width + 10, ed.Height + 10, ui.edBg);
            if (!p.text_only && !p.img_only) {
                if (p.style > 3) {if (!utils.IsKeyPressed(0x10)) gr.DrawRect(p.iBoxL + 2, p.iBoxT + 2, p.iBoxW - 4, p.iBoxH - 4, 5, RGB(0, 255, 0)); if (!utils.IsKeyPressed(0x12)) gr.DrawRect(p.tBoxL + 2, p.tBoxT + 2, p.tBoxW - 4, p.tBoxH - 4, 5, RGB(255, 0, 0));}
                else if (p.style < 4) {switch (p.style) {case 0: gr.FillSolidRect(0, p.img_t + p.imgs, p.w, 5, RGB(255, 128, 0)); break; case 1: gr.FillSolidRect(p.img_l - 5, 0, 5, p.h, RGB(255, 128, 0)); break; case 2: gr.FillSolidRect(0, p.img_t - 5, p.w, 5, RGB(255, 128, 0)); break; case 3: gr.FillSolidRect(p.img_l + p.imgs, 0, 5, p.h, RGB(255, 128, 0)); break;}}
            } gr.SetTextRenderingHint(5); gr.DrawString(editText(), font_e, ui.shadow, 16, 16, ed.Width, ed.Height, lc); gr.DrawString(editText(), font_e, ui.textcol_h, 15, 15, ed.Width, ed.Height, lc);
        }} catch (e) {}
    }

    this.toggle = function(n, ti) {
        var text_state = this.text;
        switch (n) {
            case 0:
                if (!this.bio_allmusic) this.sbar_scroll[0] = this.scrollbar_type().scroll; else this.sbar_scroll[1] = this.scrollbar_type().scroll; this.allmusic_bio = !this.allmusic_bio; window.SetProperty("SYSTEM.Allmusic Bio", this.allmusic_bio); if (this.allmusic_bio) a_txt_done = false; else l_txt_done = false; this.grab_text(false); 
                if (this.allmusic_bio != this.bio_allmusic) {if (ui.heading) this.na = this.allmusic_bio ? "  [AllMusic N/A]" : "  [Last.fm N/A]"; else {this.na = this.allmusic_bio ? "AllMusic N/A" : "Last.fm N/A"; t.paint();} timer.reset(timer.source, timer.sourcei); timer.source = window.SetTimeout(function() {t.na = ""; t.paint(); timer.source = false;}, 5000);} else this.na = "";
                if (!p.img_only && !p.text_only && this.text != text_state) img.clear_rs_cache(); img.get_images(); this.scrollbar_type().set_scroll(this.sbar_scroll[!this.bio_allmusic ? 0 : 1]); break;
            case 1:
                if (!this.alb_allmusic) this.sbar_scroll[2] = this.scrollbar_type().scroll; else this.sbar_scroll[3] = this.scrollbar_type().scroll; this.allmusic_alb = !this.allmusic_alb; window.SetProperty("SYSTEM.Allmusic Alb", this.allmusic_alb); if (this.allmusic_alb) b_txt_done = false; else lfm_alb_done = false; this.grab_text(false);
                if (this.allmusic_alb != this.alb_allmusic) {if (ui.heading) this.na = this.allmusic_alb ? "  [AllMusic N/A]" : "  [Last.fm N/A]"; else {this.na = this.allmusic_alb ? "AllMusic N/A" : "Last.fm N/A"; t.paint();} timer.reset(timer.source, timer.sourcei); timer.source = window.SetTimeout(function() {t.na = ""; t.paint(); timer.source = false;}, 5000);} else this.na = "";
                if (!p.img_only && !p.text_only && this.text != text_state) img.clear_rs_cache(); img.get_images(); this.scrollbar_type().set_scroll(this.sbar_scroll[!this.alb_allmusic ? 2 : 3]); break;
            case 2: this.lockBio = !this.lockBio; if (this.allmusic_bio) a_txt_done = false; else l_txt_done = false; this.grab_text(false); img.clear_rs_cache(); img.get_images(); but.refresh(); window.SetProperty("SYSTEM.Lock Bio", this.lockBio); break;
            case 3: this.lockRev = !this.lockRev; if (this.allmusic_alb) b_txt_done = false; else lfm_alb_done = false; this.grab_text(false); img.clear_rs_cache(); img.get_images(); but.refresh(); window.SetProperty("SYSTEM.Lock Rev", this.lockRev); break;
            case 4: ui.bothBio = !ui.bothBio; a_txt_done = false; l_txt_done = false; this.grab_text(true); img.clear_rs_cache(); img.get_images(); but.refresh(); window.SetProperty("SYSTEM.Both Bio", ui.bothBio); break;
            case 5: ui.bothRev = !ui.bothRev; this.albumFlush(); this.grab_text(true); img.clear_rs_cache(); img.get_images(); but.refresh(); window.SetProperty("SYSTEM.Both Rev", ui.bothRev); break;
            case 6:
                this.allmusic_bio = !this.allmusic_bio; window.SetProperty("SYSTEM.Allmusic Bio", this.allmusic_bio); a_txt_done = false; l_txt_done = false; this.grab_text(true); 
                if (this.allmusic_bio != this.bio_allmusic) {if (ui.heading) this.na = this.allmusic_bio ? "  [AllMusic N/A]" : "  [Last.fm N/A]"; else {this.na = this.allmusic_bio ? "AllMusic N/A" : "Last.fm N/A"; t.paint();} timer.reset(timer.source, timer.sourcei); timer.source = window.SetTimeout(function() {t.na = ""; t.paint(); timer.source = false;}, 5000);} else this.na = "";
                if (!p.img_only && !p.text_only && this.text != text_state) img.clear_rs_cache(); img.get_images(); break;
            case 7:
                this.allmusic_alb = !this.allmusic_alb; window.SetProperty("SYSTEM.Allmusic Alb", this.allmusic_alb); b_txt_done = false; lfm_alb_done = false; this.grab_text(true);
                if (this.allmusic_alb != this.alb_allmusic) {if (ui.heading) this.na = this.allmusic_alb ? "  [AllMusic N/A]" : "  [Last.fm N/A]"; else {this.na = this.allmusic_alb ? "AllMusic N/A" : "Last.fm N/A"; t.paint();} timer.reset(timer.source, timer.sourcei); timer.source = window.SetTimeout(function() {t.na = ""; t.paint(); timer.source = false;}, 5000);} else this.na = "";
                if (!p.img_only && !p.text_only && this.text != text_state) img.clear_rs_cache(); img.get_images(); break;
            case 8: p.sizes(); img.clear_rs_cache(); alb_txt_o = ""; art_txt_o = ""; this.alb_calc(); this.art_calc(); img.get_images(); window.SetProperty("SYSTEM.Layout", p.style); window.SetProperty("SYSTEM.Layout Bio", p.bioStyle); window.SetProperty("SYSTEM.Layout Rev", p.revStyle); break;
            case 9: ui.calc_text(); p.sizes(); ui.get_colors(); but.create_stars(); this.albumFlush();  if (!p.img_only ) img.clear_rs_cache(); alb_txt_o = ""; art_txt_o = ""; this.grab_text(true); img.get_images(); break;
            case 10: ui.calc_text(); p.sizes(); if (!p.img_only ) img.clear_rs_cache(); alb_txt_o = ""; art_txt_o = ""; this.alb_calc(); this.art_calc(); img.get_images(); if (p.text_only && !ui.blur) t.paint(); window.SetProperty("SYSTEM.Heading Line Hide-0 Bottom-1 Center-2", ui.heading_line); break;
            case 11: this.title = ti; if (!p.img_only ) img.clear_rs_cache(); this.albumFlush(); this.grab_text(false); img.get_images(); window.SetProperty("SYSTEM.Title Hide-0 Auto-1 Show-2", this.title); break;
            case 12: if (!ti) {if (!ui.custHeadFont) window.SetProperty("SYSTEM.Heading Style", ui.head_font_style); else window.SetProperty("_Custom.Font Heading (Name,Size,Style[0-4])", ui.cust_h_f[0] + "," + ui.cust_h_f[1] + "," + ui.cust_h_f[2])} else window.SetProperty("SYSTEM.Title Style", ui.title_font_style); ui.get_colors(); ui.get_font(); p.sizes(); if (!p.img_only ) img.clear_rs_cache(); alb_txt_o = ""; art_txt_o = ""; this.alb_calc(); this.art_calc(); img.get_images(); if (p.text_only && !ui.blur) t.paint(); break;
            case 13: p.sizes(); alb_txt_o = ""; art_txt_o = ""; this.alb_calc(); this.art_calc(); break;
            case 14: p.sizes(); img.clear_rs_cache(); if (!p.art_ix && img.artistart || !p.alb_ix && !img.artistart) {this.grab_text(false); img.get_images();} else {this.get_multi(false, p.art_ix, p.alb_ix); img.get_multi(p.art_ix);} this.alb_calc(); this.art_calc(); break;
        }
    }
}
var t = new text_manager();

function tag_writer() {
    var  arr1 = [], arr2 = [], simList = [], ix = -1, tf_a = fb.TitleFormat(p.a_tf), tf_aa = fb.TitleFormat(p.aa_tf), tf_cue = fb.TitleFormat("$ext(%path%)"), tf_l = fb.TitleFormat(p.l_tf);
    var rep = "", replace = window.GetProperty("ADV.Last.fmGenreTag Find>Replace", "alt country>alt-country|alternativ>alternative|american artist>american|americana>american|america>american|andes>andean|australian artist>australian|australia>australian|avantgarde>avant-garde|blue eyed soul>blue-eyed soul|bluesrock>blues rock|blues-rock>blues rock|boyband>boybands|brasil>brazilian|british artist>british|britpop>brit pop|canada>canadian|canterbury>canterbury scene|chill out>chillout|christmas music>christmas|christmas songs>christmas|classique>classical|composer>composers|covers>cover|cover songs>cover|doo-wop>doo wop|duets>duet|easy-listening>easy listening|england>english|eurovision song contest>eurovision|experimental hip hop>experimental hip-hop|favourite albums of all time>favourite albums|favourite lps>favourite albums|favorite song>favourite song|favourite song>favourite albums|favorit>favourite albums|favourite>favourite albums|female>female vocalists|female vocalist>female vocalists|female vocals>female vocalists|fok rock>folk rock|folk-rock>folk rock|genre: psychedelic rock>psychedelic rock|good cd>good stuff|girl group>girl groups|greek music>greek|hip hop>hip-hop|is this what they call music nowedays>is this what they call music nowadays|jamaican artist>jamaican|jamaica>jamaican|jazz-rock>jazz rock|love songs>love|male>male vocalists|male vocals>male vocalists|mis albumes favoritos>favourite albums|motown soul>motown|movie>soundtrack|my favorites>favourite albums|musical>musicals|new orleans>new orleans blues|new orleans rhythm and blues>new orleans blues|nu-metal>nu metal|one hit wonder>one hit wonders|orchestra>orchestral|pop - adult>pop|pop-rock>pop rock|post punk>post-punk|prog>progressive|progressiv>progressive|prog rock>progressive rock|prog-rock>progressive rock|punk albums>punk|R&b>rnb|relaxation>relaxing|relax>relaxing|rhythm and blues>rnb|rock - progressive>progressive rock|rock & roll>rock n roll|rock and roll>rock n roll|rock n' roll>rock n roll|rock'n'roll>rock n roll|rock progressif>progressive rock|san fransico>san francisco|singer-songwriters>singer-songwriter|soul new>soul|synth>synthesiser|synthesizer>synthesiser|synthpop>synth pop|tech-house>tech house|underrated albums>underrated|weallgetold>we all get old|xmas>christmas|allboutguitar lesson>allboutguitar|allboutguitarcom>allboutguitar|38 Special>|a good song>|acdc>|album cold play>|albums i have listened to>|albums i have on mp3>|albums i listened to>|albums i love>|albums i own>|albums i own on cd>|albums i own on vinyl>|albumsiown>|aleister crowley>|all>|barkley james harvest>|beatles>|best>|best album>|best albums ever>|best albums of all time>|best debut albums>|best top-rated albums>|bill bruford>|black sabbath>|blink 182>|bob dylan>|bob marley>|bowie>|cd i own>|christopher lee>|christine mcvie>|chupo buceta>|classic best of>|danny kirwan>|destinys child>|dylan>|ellie goulding>|elton john>|elvis costello>|featuring>|fleetwood mac>|frank zappa>|freddie mercury>|george michael and elton john>|girls aloud>|gonna listen>|grace slick>|guns n roses>|heaven and hell>|hello nadine>|intro>|j holiday>|j holiday - suffocate>|jan akkerman>|jan dismas zelenka>|jean michel jarre>|jecks>|joanne>|joe lynn turner>|jon anderson>|jonanderson>|jj cale>|jonas brothers>|judas priest>|kanye west>|kelis - kelis was here>|kesha>|lana del rey>|led zeppelin>|lesley garret>|liam gallagher>|lil boosie>|lord of the dance>|love this album>|love it>|loved>|lovely>|marillion>|michael jackson>|mia>|mike patton>|monkees>|music i love>|must-have>|my albums>|my collection>|my private work station>|my vinyl>|myhits>|n yepes>|neil young>|neil-young>|noel>|nyoung>|own cd>|own on vinyl>|paul kantner>|paul mccartney>|pavarotti>|pink>|pink floyd>|pj Harvey>|prince>|queen>|r kelly>|rahsaan patterson>|raul seixas>|robert plant>|rob halford>|roger waters>|rolling stones>|ryan adams>|selena gomez>|shirley bassey>|singles>|smashing pumpkins>|smokey robinson>|sonny terry>|special>|spice girls>|steelydan>|steve albini>|tarantino>|tatu>|the beatles>|the phantom of the opera>|to buy>|to listen>|tom petty>|tony visconti>|top cd>|trasy chapman-crossroads>|traveling wilburys>|try before i buy>|vinyl i own>|vinyl>|vocalist of the two- tone band the beat>|watson>|work bitch>|yes>|yes type>").split("|");
    for (var g = 0; g < replace.length; g ++) {rep = replace[g].split(">"); arr1.push(rep[0].trim()); arr2.push(rep[1].trim());}
    var cleanNo = window.GetProperty("ADV.Last.fmGenreTag Number Clean Up", true), runReplace = window.GetProperty("ADV.Last.fmGenreTag Run Find>Replace", true), stripNames = window.GetProperty("ADV.Last.fmGenreTag Strip Artist+Album Names", true);

    var replaceAt = function(s, n, t) {return s.substring(0, n) + t + s.substring(n + 1);}
    var cleanTagPth = function(pth, handle) {pth = pth.trim().replace(/\//g, "\\"); if (pth.toLowerCase().indexOf("%profile%") != -1) {var fbPth = fb.ProfilePath.replace(/'/g, "''").replace(/(\(|\)|\[|\]|%|,)/g, "'$1'"); if (fbPth.indexOf("$") != -1) {var fbPthSplit = fbPth.split("$"); fbPth = fbPthSplit.join("'$$'");} pth = pth.replace(/%profile%(\\|)/gi, fbPth);} pth = fb.TitleFormat(pth).EvalWithMetadb(handle) + "\\"; var c_pos = pth.indexOf(":"); pth = pth.replace(/[\/|:]/g, "-").replace(/\*/g, "x").replace(/"/g, "''").replace(/[<>]/g, "_").replace(/\?/g, "").replace(/\\\./g, "\\_").replace(/\.+\\/, "\\").replace(/\s*\\\s*/g, "\\"); if(c_pos < 3 && c_pos != -1) pth = replaceAt(pth, c_pos, ":"); return pth.trim();}
    if (p.similar && p.similar < 5) var kw = "Similar Artists: |Ähnliche Künstler: |Artistas Similares: |Artistes Similaires: |Artisti Simili: |似ているアーティスト: |Podobni Wykonawcy: |Artistas Parecidos: |Похожие исполнители: |Liknande Artister: |Benzer Sanatçılar: |相似艺术家: ";
    var replaceAt = function(s, n, t) {return s.substring(0, n) + t + s.substring(n + 1);}
    var uniq = function(a) {var j = 0, len = a.length, out = [], seen = {}; for (var i = 0; i < len; i++) {var item = a[i].toLowerCase(); if (seen[item] !== 1) {seen[item] = 1; out[j++] = a[i].titlecase().replace(/\bAor\b/g, "AOR").replace(/\bDj\b/g, "DJ").replace(/\bFc\b/g, "FC").replace(/\bIdm\b/g, "IDM").replace(/\bNwobhm\b/g, "NWOBHM").replace(/\bR&b\b/g, "R&B").replace(/\bRnb\b/g, "RnB").replace(/\bUsa\b/g, "USA").replace(/\bUs\b/g, "US").replace(/\bUk\b/g, "UK");}} return out;}

    var lfmTidy = function(n, a, l) {
        var i = 0, j = 0; n = n.split('\n')[0].trim().split(", "); try {
        if (cleanNo) {for (i = 0; i < n.length; i++) {n[i] = n[i].replace(/\b(\d\d\d\d).+\b/g, "$1").replace(/\b(\d\d)'s\b/gi, "$1s").replace(/^\b(twenties|192\d(s|))\b/gi, "20s").replace(/^\b(thirties|193\d(s|))\b/gi, "30s").replace(/^\b(forties|194\d(s|))\b/gi, "40s").replace(/^\b(fifties|195\d(s|))\b/gi, "50s").replace(/^\b(sixties|196\d(s|))\b/gi, "60s").replace(/^\b(seventies|197\d(s|))\b/gi, "70s").replace(/^\b(eighties|198\d(s|))\b/gi, "80s").replace(/^\b(nineties|199\d(s|))\b/gi, "90s").replace(/^\b(noughties|200\d(s|))\b/gi, "00s").replace(/^\b(tens|201\d(s|))\b/gi, "10s"); if ((/\b\d\ds\b/).test(n[i])) n[i] = n[i].replace(/\b(\d\ds).+\b/, "$1"); else n[i] = n[i].replace(/.*\d.*/, "");}}
        if (stripNames) {i = n.length; while (i--) if (n[i].toLowerCase() == a.toLowerCase() || n[i].toLowerCase() == p.removeDiacritics(a).toLowerCase()) n.splice(i, 1);} if (stripNames) {i = n.length; while (i--) if (n[i].toLowerCase() == l.toLowerCase()) n.splice(i, 1);}
        if (runReplace) for (i = 0; i < n.length; i++) for (j = 0; j < arr1.length; j++) if (n[i].toLowerCase() == arr1[j].toLowerCase()) n[i] = arr2[j];
        i = n.length; while (i--) if (!n[i]) n.splice(i, 1); n = uniq(n); return n;} catch (e) {return n;}
    }

    this.check = function(handles) {
        if (!handles) return; var  a = "", a_o = "####",  rec = 0, sa = [], simArr = [], writeSent = false;
        for (var i = 0; i < handles.Count; i++) {a = tf_a.EvalWithMetadb(handles.Item(i)).toUpperCase(); if (a != a_o) {a_o = a; sa[i] = ""; var lfmBio = cleanTagPth(p.lfmBioPth, handles.Item(i)) + a.clean() + ".txt"; if (p.file(lfmBio)) {var lfm_a = utils.ReadTextFile(lfmBio), sim = lfm_a.match(RegExp(kw)); if (sim) {sim = sim.toString(); ix = lfm_a.lastIndexOf(sim); if (ix != -1) {sa[i] = lfm_a.substring(ix + sim.length); sa[i] = sa[i].split('\n')[0].trim().split(", "); if (sa[i].length > 4) simArr.push(a);}}}}}
        if (simArr.length) {i = 0; timer.reset(timer.sim1, timer.sim1i); timer.sim1 = window.SetInterval(function() {if (i < simArr.length) {var lfm_similar = new lfm_similar_artists(function() {lfm_similar.on_state_change();}, lfm_similar_search_done); lfm_similar.Search(simArr[i], simArr.length, handles, 4); i++;} else timer.reset(timer.sim1, timer.sim1i);}, simArr.length < 100 ? 20 : 300);} else this.write_tags(handles);
        var lfm_similar_search_done = function(res1, res2, p_done, p_handles) {rec++; if (!timer.sim2) timer.sim2 = window.SetTimeout(function() {writeSent = true; tag.write_tags(p_handles); timer.sim2 = false;}, 60000); simList.push({name:res1,similar:res2}); if (p_done == rec && !writeSent) {timer.reset(timer.sim2, timer.sim2i); tag.write_tags(p_handles);}}
    }

    this.write_tags = function(handles) {
        if (!handles) return; var  a = "", a_o = "####",  aa = "", aa_o = "####", albGenre_am = [], albTags = [], amMoods = [], amRating = [], amThemes = [], artGenre_am = [], artTags = [], cue = [],  l = "", l_o = "####", rem = [], sa = [], tags = [];
        for (var i = 0; i < handles.Count; i++) {
            a = tf_a.EvalWithMetadb(handles.Item(i)).toUpperCase(); aa = tf_aa.EvalWithMetadb(handles.Item(i)).toUpperCase(); cue[i] = tf_cue.EvalWithMetadb(handles.Item(i)).toLowerCase() == "cue"; l = tf_l.EvalWithMetadb(handles.Item(i)).toUpperCase();
            if (!this.alb_strip) l = l.replace(/CD(\s*\d|\.0\d)|CD\s*(One|Two|Three)|Disc\s*\d|Disc\s*(III|II|I|One|Two|Three)\b/gi,"").replace(/\(\s*\)|\[\s*\]/g, " ").replace(/\s\s+/g, " ").replace(/-\s*$/g, " ").trim();
            else l = l.replace(/CD(\s*\d|\.0\d)|CD\s*(One|Two|Three)|Disc\s*\d|Disc\s*(III|II|I|One|Two|Three)\b|(Bonus\s*Track|Collector's|(Digital\s*|Super\s*|)Deluxe|Digital|Expanded|Limited|Platinum|Reissue|Special)\s*(Edition|Version)|(Bonus\s*(CD|Disc))|\d\d\w\w\s*Anniversary\s*(Expanded\s*|Re(-|)master\s*|)(Edition|Re(-|)master|Version)|((19|20)\d\d(\s*|\s*-\s*)|)(Digital(ly|)\s*|)(Re(-|)master(ed|)|Re(-|)recorded)(\s*Edition|\s*Version|)|\(Deluxe\)|\(Mono\)|\(Reissue\)|\(Revisited\)|\(Stereo\)|\(Web\)|\[Deluxe\]|\[Mono\]|\[Reissue\]|\[Revisited\]|\[Stereo\]|\[Web\]/gi,"").replace(/\(\s*\)|\[\s*\]/g, " ").replace(/\s\s+/g, " ").replace(/-\s*$/g, " ").trim();
            if (a != a_o) {
                a_o = a;
                if (p.artGenre_lfm != 0 || p.similar && p.similar < 5) {
                    artTags[i] = ""; sa[i] = ""; var lfmBio = cleanTagPth(p.lfmBioPth, handles.Item(i)) + a.clean() + ".txt";
                    if (p.file(lfmBio)) {
                        var lfm_a = utils.ReadTextFile(lfmBio);
                        if (p.artGenre_lfm != 0) {ix = lfm_a.lastIndexOf("Top Tags: "); if (ix != -1) {artTags[i] = lfm_a.substring(ix + 10); artTags[i] = lfmTidy(artTags[i], a, l);}}
                        if (p.similar && p.similar < 5) {var sim = lfm_a.match(RegExp(kw)); if (sim) {sim = sim.toString(); ix = lfm_a.lastIndexOf(sim); if (ix != -1) {sa[i] = lfm_a.substring(ix + sim.length); sa[i] = sa[i].split('\n')[0].trim().split(", ");} if (sa[i].length > 4) {sa[i] = ""; for (k = 0; k < simList.length; k++) {if (simList[k].name == a) {sa[i] = simList[k].similar; break;}}} sa[i].length = Math.min(p.similar, sa[i].length);}}
                    }
                }
                if (p.similar > 4) {
                    var lfmSim = cleanTagPth(p.lfmSimPth, handles.Item(i)) + a.clean() + " And Similar Artists.json", nm = ""; sa[i] = "";
                    if (p.file(lfmSim)) {var lfm_s = p.json_parse(utils.ReadTextFile(lfmSim)), newStyle = false; if (lfm_s) {if (lfm_s[0].hasOwnProperty('name')) {newStyle = true; lfm_s.shift();} var simNo = Math.min(p.similar, lfm_s.length); if (simNo) sa[i] = []; for (var j = 0; j < simNo; j++) {nm = newStyle ? lfm_s[j].name : lfm_s[j]; if (nm) sa[i].push(nm);} if (!sa[i].length) sa[i] = "";}}
                }
                if (p.artGenre_am != 0) {
                    artGenre_am[i] = ""; var amBio = cleanTagPth(p.amBioPth, handles.Item(i)) + a.clean() + ".txt";
                    if (p.file(amBio)) {var am_a = utils.ReadTextFile(amBio); ix = am_a.lastIndexOf("Genre: "); if (ix != -1) {artGenre_am[i] = am_a.substring(ix + 7); artGenre_am[i] = artGenre_am[i].split('\n')[0].trim().split(", ");}}
                }
            } else {artTags[i] = artTags[i - 1]; sa[i] = sa[i - 1]; artGenre_am[i] = artGenre_am[i - 1];}
            if (aa + l != aa_o + l_o) {
                aa_o = aa; l_o = l;
                if (p.albGenre_am != 0 || p.mood != 0 || p.theme != 0 || p.rating != 0) {
                    albGenre_am[i] = ""; amMoods[i] = ""; amThemes[i] = ""; amRating[i] = ""; var amRev = cleanTagPth(p.amRevPth, handles.Item(i)) + aa.clean() + " - " + l.clean() + ".txt";
                    if (p.file(amRev)) {
                        var aRev = utils.ReadTextFile(amRev);
                        if (p.albGenre_am != 0) {ix = aRev.lastIndexOf("Genre: "); if (ix != -1) {albGenre_am[i] = aRev.substring(ix + 7); albGenre_am[i] = albGenre_am[i].split('\n')[0].trim().split(", ");}}
                        if (p.mood != 0) {ix = aRev.lastIndexOf("Album Moods: "); if (ix != -1) {amMoods[i] = aRev.substring(ix + 13); amMoods[i] = amMoods[i].split('\n')[0].trim().split(", ");}}
                        if (p.theme != 0) {ix = aRev.lastIndexOf("Album Themes: "); if (ix != -1) {amThemes[i] = aRev.substring(ix + 14); amThemes[i] = amThemes[i].split('\n')[0].trim().split(", ");}}
                        if (p.rating != 0) {var s = aRev.indexOf(">> Album rating: ") + 17, f = aRev.indexOf(" <<"); if (s != -1 && f != -1 && f > s) {amRating[i] = aRev.substring(s, f).trim() * 2; if (amRating[i] == 0) amRating[i] = "";}}
                    }
                }
                if (p.albGenre_lfm != 0) {
                    albTags[i] = ""; var lfmRev = cleanTagPth(p.lfmRevPth, handles.Item(i)) + aa.clean() + " - " + l.clean() + ".txt";
                    if (p.file(lfmRev)) {var lRev = utils.ReadTextFile(lfmRev); ix = lRev.lastIndexOf("Top Tags: "); if (ix != -1) {albTags[i] = lRev.substring(ix + 10); albTags[i] = lfmTidy(albTags[i], aa, l);}}
                }
            } else {albGenre_am[i] = albGenre_am[i - 1]; amMoods[i] = amMoods[i - 1]; amThemes[i] = amThemes[i- 1]; amRating[i] = amRating[i - 1]; albTags[i] = albTags[i - 1];}
            var tg = {}, albR_amkey = "", artG_lfkey = "", sikey = "", artG_amkey = "", albG_amkey = "", albM_amkey = "", albT_amkey = "", albG_lfkey = "";
            if (!cue[i] && (amRating[i] || artTags[i] || sa[i] || artGenre_am[i] || albGenre_am[i] || amMoods[i] || amThemes[i] || albTags[i])) {tg = {};
                albR_amkey = amRating[i] ? p.rating_nm : "##Null##"; tg[albR_amkey] = amRating[i];
                artG_lfkey = artTags[i] ? p.artGenre_lfm_nm : "##Null##"; tg[artG_lfkey] = artTags[i];
                sikey = sa[i] ? p.similar_nm : "##Null##"; tg[sikey] = sa[i];
                artG_amkey = artGenre_am[i] ? p.artGenre_am_nm : "##Null##"; tg[artG_amkey] = artGenre_am[i];
                albG_amkey = albGenre_am[i] ? p.albGenre_am_nm : "##Null##"; tg[albG_amkey] = albGenre_am[i];
                albM_amkey = amMoods[i] ? p.mood_nm : "##Null##"; tg[albM_amkey] = amMoods[i];
                albT_amkey = amThemes[i] ? p.theme_nm : "##Null##"; tg[albT_amkey] = amThemes[i];
                albG_lfkey = albTags[i] ? p.albGenre_lfm_nm : "##Null##"; tg[albG_lfkey] = albTags[i];
                tags.push(tg);
            } else rem.push(i);
        }
		i = rem.length; while (i--)  handles.RemoveById(rem[i]);
		if (handles.Count) handles.UpdateFileInfoFromJSON(JSON.stringify(tags)); if (handles) handles.Dispose();
    }
}
var tag = new tag_writer();
    
this.text_box = function() {
    var init_x = 0, init_y = 0, x_init = 0, y_init = 0, si = "", st = ""; this.down = false;

    var sizes = function(bypass) {p.sizes(bypass); but.refresh(); t.paint();}
    this.lbtn_dn = function(x, y)  {p.newStyle = false; if (!utils.IsKeyPressed(0x11)) return; this.down = true; init_x = x; init_y = y; x_init = x; y_init = y;}

    this.lbtn_up = function(x, y)  {
        if (!this.down) return; window.SetCursor(32512); this.down = false; img.resetFade = true;
        if (p.style > 3) {
            var obj = p.style == 4 ? p.overlay : p.styles[p.style - 5];
            var sv = false, imL = Math.round(p.im_l * p.w), imR = Math.round(p.im_r * p.w), imT = Math.round(p.im_t * p.h), imB = Math.round(p.im_b * p.h), txL = Math.round(p.tx_l * p.w), txR = Math.round(p.tx_r * p.w), txT = Math.round(p.tx_t * p.h), txB = Math.round(p.tx_b * p.h);
            if (p.h > txB + txT + 30 && p.w > txR + txL + 30) {obj.txL = p.tx_l; obj.txR = p.tx_r; obj.txT = p.tx_t; obj.txB = p.tx_b; sv = true;}
            if (p.h > imB + imT + 30 && p.w > imR + imL + 30) {obj.imL = p.im_l; obj.imR = p.im_r; obj.imT = p.im_t; obj.imB = p.im_b; sv = true;}
            if (sv) {window.SetProperty(p.style == 4 ? "SYSTEM.Overlay" : "SYSTEM.Freestyle Custom", JSON.stringify(p.style == 4 ? p.overlay : p.styles));}
            else {p.im_l = Math.min(Math.max(obj.imL, 0), 1); p.im_r = Math.min(Math.max(obj.imR, 0), 1); p.im_t = Math.min(Math.max(obj.imT, 0), 1); p.im_b = Math.min(Math.max(obj.imB, 0), 1); p.tx_l = Math.min(Math.max(obj.txL, 0), 1); p.tx_r = Math.min(Math.max(obj.txR, 0), 1); p.tx_t = Math.min(Math.max(obj.txT, 0), 1); p.tx_b = Math.min(Math.max(obj.txB, 0), 1);}
        } else window.SetProperty("SYSTEM.Layout Image Size 0-1", p.rel_imgs); t.toggle(14);
    }

    this.move = function(x, y) {
        if (p.style < 4 || !utils.IsKeyPressed(0x11) || utils.IsKeyPressed(0x12)) return;
        if (!this.down) {
            st = y > p.tBoxT - 5 && y < p.tBoxT + 5 && x > p.tBoxL + 10 && x < p.tBoxL + p.tBoxW - 10 ? "top" :
            y > p.tBoxT - 5 && y < p.tBoxT + 15 && x > p.tBoxL && x < p.tBoxL + 10 ? "nw" :
            y > p.tBoxT - 5 && y < p.tBoxT + 15 && x > p.tBoxL + p.tBoxW - 10 && x < p.tBoxL + p.tBoxW ? "ne" :
            y > p.tBoxT + p.tBoxH - 5 && y < p.tBoxT + p.tBoxH + 5 && x > p.tBoxL + 10 && x < p.tBoxL + p.tBoxW - 10 ? "bottom" :
            y > p.tBoxT + p.tBoxH - 15 && y < p.tBoxT + p.tBoxH + 5 && x > p.tBoxL && x < p.tBoxL + 10 ? "sw" :
            y > p.tBoxT + p.tBoxH - 15 && y < p.tBoxT + p.tBoxH + 5 && x > p.tBoxL + p.tBoxW - 10 && x < p.tBoxL + p.tBoxW ? "se" :
            y > p.tBoxT + 10 && y < p.tBoxT + p.tBoxH && x > p.tBoxL - 5 && x < p.tBoxL + 5 ? "left" : 
            y > p.tBoxT + 10 && y < p.tBoxT + p.tBoxH && x > p.tBoxL + p.tBoxW - 5 && x < p.tBoxL + p.tBoxW + 5 ? "right" :
            y > p.tBoxT + 20 && y < p.tBoxT + p.tBoxH - 20 && x > p.tBoxL + 20 && x < p.tBoxL + p.tBoxW - 20 ? "all": "";
            if (st == "top" || st == "bottom") window.SetCursor(32645); if (st == "left" || st == "right") window.SetCursor(32644); if (st == "all") window.SetCursor(32646);
            if (st == "nw" || st == "se") window.SetCursor(32642); if (st == "ne" || st == "sw") window.SetCursor(32643);
        } if (!this.down) return; var txT = Math.round(p.tx_t * p.h), txB = Math.round(p.tx_b * p.h), txL = Math.round(p.tx_l * p.w), txR = Math.round(p.tx_r * p.w);
        switch (st){
            case "top": if (y > p.h - txB - p.minH) break; p.tx_t = Math.min(Math.max(y / p.h, 0), 1); break;
            case "nw": if (y < p.h - txB - p.minH) p.tx_t = Math.min(Math.max(y / p.h, 0), 1); if (x > p.w - txR - 30) break; p.tx_l = Math.min(Math.max(x / p.w, 0), 1); break;
            case "ne": if (y < p.h - txB - p.minH) p.tx_t = Math.min(Math.max(y / p.h, 0), 1); if (x < txL + 30) break; p.tx_r = Math.min(Math.max((p.w - x) / p.w, 0), 1); break;
            case "left": if (x > p.w - txR - 30) break; p.tx_l = Math.min(Math.max(x / p.w, 0), 1); break;
            case "bottom": if (y < txT + p.minH) break; p.tx_b = Math.min(Math.max((p.h - y) / p.h, 0), 1); break;
            case "sw": if (x < p.w - txR - 30) p.tx_l = Math.min(Math.max(x / p.w, 0), 1); if (y < txT + p.minH) break; p.tx_b = Math.min(Math.max((p.h - y) / p.h, 0), 1); break;
            case "se": if (y > txT + p.minH) p.tx_b = Math.min(Math.max((p.h - y) / p.h, 0), 1); if (x < txL + 30) break; p.tx_r = Math.min(Math.max((p.w - x) / p.w, 0), 1); break;
            case "right": if (x < txL + 30) break; p.tx_r = Math.min(Math.max((p.w - x) / p.w, 0), 1); break;
            case "all": if ((txT >= p.h - p.tBoxH && y - init_y > 0) || (txL >= p.w - p.tBoxW && x - init_x > 0)) break; txT += (y - init_y); p.tx_t = Math.min(Math.max(txT / p.h, 0), 1); txL += (x - init_x); p.tx_l = Math.min(Math.max(txL / p.w, 0), 1); txB = p.h - Math.max(txT, 0) - p.tBoxH; p.tx_b = Math.min(Math.max(txB / p.h, 0), 1); txR = p.w - Math.max(txL, 0) - p.tBoxW; p.tx_r = Math.min(Math.max(txR / p.w, 0), 1); break;
        } sizes(true); init_x = x; init_y = y;
    }

    this.img_move = function(x, y) {
        switch (true) {
            case p.style > 3:
                if (!utils.IsKeyPressed(0x11) || utils.IsKeyPressed(0x10)) break;
                if (!this.down) {
                    si = y > p.iBoxT - 5 && y < p.iBoxT + 5 && x > p.iBoxL + 10 && x < p.iBoxL + p.iBoxW - 10 ? "top" :
                    y > p.iBoxT - 5 && y < p.iBoxT + 15 && x > p.iBoxL && x < p.iBoxL + 10 ? "nw" :
                    y > p.iBoxT - 5 && y < p.iBoxT + 15 && x > p.iBoxL + p.iBoxW - 10 && x < p.iBoxL + p.iBoxW ? "ne" :
                    y > p.iBoxT + p.iBoxH - 5 && y < p.iBoxT + p.iBoxH + 5 && x > p.iBoxL + 10 && x < p.iBoxL + p.iBoxW - 5 ? "bottom" :
                    y > p.iBoxT + p.iBoxH - 15 && y < p.iBoxT + p.iBoxH + 5 && x > p.iBoxL && x < p.iBoxL + 10 ? "sw" :
                    y > p.iBoxT + p.iBoxH - 15 && y < p.iBoxT + p.iBoxH + 5 && x > p.iBoxL + p.iBoxW - 10 && x < p.iBoxL + p.iBoxW ? "se" :
                    y > p.iBoxT && y < p.iBoxT + p.iBoxH && x > p.iBoxL - 5 && x < p.iBoxL + 5 ? "left" : 
                    y > p.iBoxT && y < p.iBoxT + p.iBoxH && x > p.iBoxL + p.iBoxW - 5 && x < p.iBoxL + p.iBoxW + 5 ? "right" :
                    y > p.iBoxT + 20 && y < p.iBoxT + p.iBoxH - 20 && x > p.iBoxL + 20 && x < p.iBoxL + p.iBoxW - 20 ? "all": "";
                    if (si == "top" || si == "bottom") window.SetCursor(32645); if (si == "left" || si == "right") window.SetCursor(32644); if (si == "all") window.SetCursor(32646);
                    if (si == "nw" || si == "se") window.SetCursor(32642); if (si == "ne" || si == "sw") window.SetCursor(32643);
                } if (!this.down) return;
                var imT = Math.round(p.im_t * p.h), imB = Math.round(p.im_b * p.h), imL = Math.round(p.im_l * p.w), imR = Math.round(p.im_r * p.w);
                switch (si){
                    case "top": if (y > p.h - imB - 30) break; p.im_t = Math.min(Math.max(y / p.h, 0), 1); break;
                    case "nw": if (y < p.h - imB - 30) p.im_t = Math.min(Math.max(y / p.h, 0), 1); if (x > p.w - imR - 30) break; p.im_l = Math.min(Math.max(x / p.w, 0), 1); break;
                    case "ne": if (y < p.h - imB - 30) p.im_t = Math.min(Math.max(y / p.h, 0), 1); if (x < imL + 30) break; p.im_r = Math.min(Math.max((p.w - x) / p.w, 0), 1); break;
                    case "left": if (x > p.w - imR - 30) break; p.im_l = Math.min(Math.max(x / p.w, 0), 1); break;
                    case "bottom": if (y < imT + 30) break; p.im_b = Math.min(Math.max((p.h - y) / p.h, 0), 1); break;
                    case "sw": if (x < p.w - imR - 30) p.im_l = Math.min(Math.max(x / p.w, 0), 1); if (y < imT + 30) break; p.im_b = Math.min(Math.max((p.h - y) / p.h, 0), 1); break;
                    case "se":if (y > imT + 30) p.im_b = Math.min(Math.max((p.h - y) / p.h, 0), 1); if (x < imL + 30) break; p.im_r = Math.min(Math.max((p.w - x) / p.w, 0), 1); break;
                    case "right": if (x < imL + 30) break; p.im_r = Math.min(Math.max((p.w - x) / p.w, 0), 1); break;
                    case "all": if ((imT >= p.h - p.iBoxH && y - y_init > 0) || (imL >= p.w - p.iBoxW && x - x_init > 0)) break;imT += (y - y_init); p.im_t = Math.min(Math.max(imT / p.h, 0), 1); imB = p.h - Math.max(imT, 0) - p.iBoxH; p.im_b = Math.min(Math.max(imB / p.h, 0), 1); imL += (x - x_init); p.im_l = Math.min(Math.max(imL / p.w, 0), 1); imR = p.w - Math.max(imL, 0) - p.iBoxW; p.im_r = Math.min(Math.max(imR / p.w, 0), 1); break;
                } sizes(true);
                break;
            case p.style < 4:
                if (!utils.IsKeyPressed(0x11)) break;
                if (!this.down) {switch (p.style) {case 0: si = y > p.img_t + p.imgs && y < p.img_t + p.imgs + 5; if (si) window.SetCursor(32645); break; case 1: si = x > p.img_l - 5 && x < p.img_l;  if (si) window.SetCursor(32644); break; case 2: si = y > p.img_t - 5 && y < p.img_t; if (si) window.SetCursor(32645); break; case 3: si = x > p.img_l + p.imgs && x < p.img_l + p.imgs + 5; if (si) window.SetCursor(32644); break;}}
                if (!this.down || !si) return; 
                switch (p.style) {case 0: var img_h = p.rel_imgs * p.h; img_h += y - y_init; p.rel_imgs = img_h / p.h; break;case 1: var img_w = p.rel_imgs * p.w; img_w += x_init - x; p.rel_imgs = img_w / p.w; break; case 2: var img_h = p.rel_imgs * p.h; img_h += y_init - y; p.rel_imgs = img_h / p.h; break; case 3: var img_w = p.rel_imgs * p.w; img_w += x - x_init; p.rel_imgs = img_w / p.w; break;}
                p.rel_imgs = Math.max(Math.min(p.rel_imgs, 0.9), 0.1); sizes();
                break;
        } x_init = x; y_init = y;
    }
}
var tb = new text_box();

function library_manager() {
    var db_lib, i = 0, q = "", ql; this.update = true; this.get_lib_items = function() {if (!this.update) return db_lib; this.update = false; if (db_lib) db_lib.Dispose(); db_lib = fb.GetLibraryItems(); return db_lib;} 
    this.in_library = function (type, a, l) {
        switch (type) {
            case 0: q = ""; for (i = 0; i < p.artFields.length; i++) q += (i ? " OR " : "") + p.artFields[i] + " IS " + a; var items = fb.CreateHandleList(); try {items = fb.GetQueryItems(this.get_lib_items(), q)} catch (e) {} if (!items.Count) return false; return true; break;
            case 1: q = ""; ql = ""; for (i = 0; i < p.albartFields.length; i++) q += (i ? " OR " : "") + p.albartFields[i] + " IS " + a; for (i = 0; i < p.albFields.length; i++) ql += (i ? " OR " : "") + p.albFields[i] + " IS " + l; var items = fb.CreateHandleList(); try {items = fb.GetQueryItems(this.get_lib_items(), "(" + q + ") AND (" + ql + ")")} catch (e) {} if (!items.Count) return false; return items.Count;
            case 2: q = "(" + "\"" + p.def_tf[0].tf + "\"" + " IS " + a + ") AND (" + "\"" + p.def_tf[2].tf + "\"" + " IS " + l + ")"; var items = fb.CreateHandleList(); try {items = fb.GetQueryItems(this.get_lib_items(), q)} catch (e) {} if (!items.Count) return false; return items.Item(0);
}}}
var lib = new library_manager();

function image_manager() {
    var a_im = [], a_img = [], alb_id = "", alb_id_o = "", all_files_o_length = 0, alpha = 255, artist = "", artist_o = "", artist_img = false, a_sz = [], b_aim = [], b_fim = [], bor_w1 = 0, bor_w2 = 0, chk_arr = [], core_img = [], counter = 0, f_blur = false, f_im = [], f_sz = [], fade_mask = false, fe_done = "", folder = "", folderSup = "", g_valid_tid = 0, i_x = 0, ix = 0, image_path_o = [], imgb = 0, imgID = "", imgID_o = "", init = true, new_BlurAlb = false, nw = 0, refl_mask = false, rsimgA = [], rsimgL = [], sh_img = false, update = 0, validate = [], wID1 = 0, wID2 = 0, x_l = 0, x_r = 0, xa = 0, xf = 0, y_b = 0, y_t = 0, ya = 0, yf = 0;
    var blurAutofill = window.GetProperty("ADV.Image Blur Background Auto-Fill", false), covBlur = window.GetProperty(" Image Blur Background Always Use Cover", false), cover_id = 0, ext = [".jpg", ".png", ".gif", ".bmp", ".jpeg"], reflSetup = window.GetProperty(" Image Reflection Setting (0-100)", "Strength,14.5,Size,100,Gradient,10").split(","), transLevel = Math.min(Math.max((100 - window.GetProperty(" Image Smooth Transition Level (0-100)", 92)), 0.1), 100), transIncr = Math.pow(284.2171 / transLevel, 0.0625); if (transLevel == 100) transLevel = 255;
    var reflAlpha = parseFloat(reflSetup[1]), reflSlope = parseFloat(reflSetup[5]), reflSz = parseFloat(reflSetup[3]); if (isNaN(reflAlpha)) reflAlpha = 14.5; reflAlpha =  255 * reflAlpha / 100; reflAlpha = Math.max(Math.min(reflAlpha, 255), 0);  if (isNaN(reflSlope)) reflSlope = 10; reflSlope /= 10; reflSlope = Math.max(Math.min(reflSlope - 1, 9), -1); if (isNaN(reflSz)) reflSz = 100; reflSz /= 100; reflSz = Math.max(Math.min(reflSz, 1), 0.1);
    var userStubFile = fb.ProfilePath + "yttm\\front_cover_stub_user.png"; var userStub = p.file(userStubFile) ? gdi.Image(userStubFile) : false;
    this.a_run = true; this.arr = []; this.artistart = window.GetProperty("SYSTEM.Artist Art", false); this.border = window.GetProperty("SYSTEM.Image Border-1 Shadow-2 Both-3", 0); this.bp = false; this.covType = window.GetProperty("SYSTEM.Cover Type", 0); this.displayed_other_panel = null; this.get = true; this.nh = 0; this.reflection = window.GetProperty("SYSTEM.Image Reflection", false); this.reflectionType = window.GetProperty("SYSTEM.Image Reflection Type", 0); this.resetFade = false; this.smoothTrans = window.GetProperty("SYSTEM.Image Smooth Transition", false);

    this.arr_contains = function(arr, item) {for (var i = 0; i < arr.length; i++) if (arr[i] == item) return true; return false;}
    this.alignAuto = window.GetProperty("SYSTEM.Image Align Auto", true); this.autoAlign = window.GetProperty("SYSTEM.Image Align With Text", false); this.alignH = window.GetProperty("SYSTEM.Image Alignment Horizontal", 1); this.alignV = window.GetProperty("SYSTEM.Image Alignment Vertical", 1); this.artCropDual = window.GetProperty("SYSTEM.Photo Crop [Dual Mode]", false); this.artCropImgOnly = window.GetProperty("SYSTEM.Photo Crop [Image Only]", false); this.covCropDual = window.GetProperty("SYSTEM.Cover Crop [Dual Mode]", false); this.covCropImgOnly = window.GetProperty("SYSTEM.Cover Crop [Image Only]", false); this.crop = false;
    this.artist_reset = function() {this.blurCheck(); artist_o = artist; artist = name.artist(); var new_artist = artist && artist != artist_o || !artist || covBlur && ui.blur && alb_id != alb_id_o; timer.step = 0; timer.men_step = 0; if (new_artist) {folderSup = ""; folder = p.cleanPth(p.imgArtPth); this.clear_art_cache(); if (p.lfm_img) this.a_run = true; if (!this.arr.length) {all_files_o_length = 0; ix = 0;}}}
    this.blurCheck = function() {if (!(covBlur && ui.blur) && !this.smoothTrans) return; alb_id_o = alb_id; alb_id = !p.eval("[%album%]") ? p.eval("%album artist%%path%") : p.eval("%album artist%%album%%discnumber%%date%"); alb_id += this.covType; if (alb_id != alb_id_o) {new_BlurAlb = true; t.mulAlbum = false;}}
    this.change = function(incr) {ix += incr; if (ix < 0) ix = this.arr.length - 1; else if (ix >= this.arr.length) ix = 0; var i = 0; while (this.displayed_other_panel == this.arr[ix] && i < this.arr.length) {ix += incr; if (ix < 0) ix = this.arr.length - 1; else if (ix >= this.arr.length) ix = 0; i++;} this.set_chk_arr(this.arr[ix]); this.artist_image();}
    this.chk_arr = function(info) {if (t.block()) return; if (this.arr.length < 2 || !this.artistart || p.text_only || !p.lfm_img) return; if (!this.arr_contains(validate, info[0])) validate.push(info[0]); this.displayed_other_panel = info[1]; if (!wID1) wID1 = info[0]; wID2 = (wID1== info[0]) ? 0 : info[0]; if (this.arr[ix] != info[2] && !wID2) {chk_arr = [window.ID, this.arr[ix], this.displayed_other_panel]; window.NotifyOthers("chk_arr_jb", chk_arr); } if (window.ID > info[0]) return; if (this.arr[ix] == this.displayed_other_panel && validate.length < 2) this.change(1);}
	var clamp = function(num, min, max) {num = num <= max ? num : max; num = num >= min ? num : min; return num;}
    this.clear_a_rs_cache = function() {for (var i = 0; i < a_im.length; i++) {rsimgA[i] = false; if (a_im[i]) a_im[i].Dispose(); a_im = [];} for (i = 0; i < b_aim.length; i++) {if (b_aim[i]) b_aim[i].Dispose(); b_aim = [];} rsimgL[0] = false; if (f_im[0]) f_im[0].Dispose(); f_im[0] = false; if (b_fim[0]) b_fim[0].Dispose(); b_fim[0] = false;}
    this.clear_art_cache = function() {if (artist_img) artist_img.Dispose(); for (var i = 0; i < a_img.length; i++) if (a_img[i]) a_img[i].Dispose(); a_img = []; this.arr = []; validate = []; if (core_img[0]) core_img[0].Dispose(); artist_img = core_img[0] = false; this.clear_a_rs_cache();}
    this.clear_c_rs_cache = function() {for (var i = 1; i < f_im.length; i++) {rsimgL[i] = false; if (f_im[i]) f_im[i].Dispose(); f_im[i] = false;} for (i = 1; i < b_fim.length; i++) {if (b_fim[i]) b_fim[i].Dispose(); b_fim[i] = false;}}
    this.clear_cov_cache = function() {for (var i = 1; i < core_img.length; i++) {if (core_img[i]) core_img[i].Dispose(); core_img[i] = false;} this.clear_c_rs_cache();}
    this.clear_rs_cache = function() {this.clear_c_rs_cache(); this.clear_a_rs_cache();}
    this.create_images = function() {var cc = StringFormat(1, 1), font1 = gdi.Font("Segoe UI", 270, 1), font2 = gdi.Font("Segoe UI", 120, 1), font3 = gdi.Font("Segoe UI", 200, 1), font4 = gdi.Font("Segoe UI", 90, 1), gb, tcol = !ui.blur_dark && !ui.blur_light || (this.border != 1 && this.border != 3) ? ui.textcol : ui.dui ? window.GetColourDUI(0) : window.GetColourCUI(0); this.noimg = ["COVER", "PHOTO", "SELECTION"]; for (var i = 0; i < this.noimg.length; i++) {var n = this.noimg[i]; this.noimg[i] = gdi.CreateImage(500, 500); gb = this.noimg[i].GetGraphics(); gb.SetSmoothingMode(2); if (!ui.blur_dark && !ui.blur_light || this.border == 1 || this.border == 3) {gb.FillSolidRect(0, 0, 500, 500, tcol); gb.FillGradRect(-1, 0, 505, 500, 90, ui.backcol & 0xbbffffff, ui.backcol, 1.0);} gb.SetTextRenderingHint(3); gb.DrawString("NO", i == 2 ? font3 : font1, tcol & 0x25ffffff, 0, 0, 500, 275, cc); gb.DrawString(n, i == 2 ? font4 : font2, tcol & 0x20ffffff, 2.5, 175, 500, 275, cc); gb.FillSolidRect(60, 388, 380, 50, tcol & 0x15ffffff); this.noimg[i].ReleaseGraphics(gb);} this.get = true;}; this.create_images();
    this.defStub = function(n) {if (p.handle(p.focus)) {if (!n && userStub) return userStub; return this.noimg[n].Clone(0, 0, this.noimg[n].Width, this.noimg[n].Height);} else {return this.noimg[2].Clone(0, 0, this.noimg[2].Width, this.noimg[2].Height);}}
    var exclArr = [6467, 6473, 6500, 24104, 35875, 37235, 47700, 68626, 86884, 92172];
    this.fresh = function() {counter++; if (counter > p.cycle_photo) counter = 0; if (t.block() || !p.cyc || !this.artistart || counter != p.cycle_photo || this.arr.length < 2 || p.text_only || (fb.IsPlaying ? fb.PlaybackTime - timer.step < p.cycle_photo / 2 : false) || !p.lfm_img || ui.zoom()) return; this.change(1); counter = 0;}
    this.get_images = function() {if (p.text_only && !ui.blur) return; if (this.artistart && p.lfm_img) {if (!p.art_ix) this.artist_reset(); this.grab_a_img();} else this.grab_f_img();}
    this.get_img_fallback = function() {if (t.scrollbar_type().draw_timer) return; if (!p.multi_new()) return; if (!this.get) return; update = 0; this.get_images(); this.get = false;}
    this.grab = function(force) {update = 1; if (t.block()) return this.get = true; this.grab_a_img(); if (force) this.grab_f_img(); update = 0;}
    this.grab_a_img = function() {if (!this.artistart || p.text_only && !ui.blur) return; if (this.a_run || update) {this.a_run = false; if (artist) this.read_arr();} this.set_chk_arr(p.lfm_img ? this.arr[ix] : null); this.artist_image();}
    this.paint = function() {if (!this.smoothTrans) {alpha = 255; t.paint(); return;} imgID_o = imgID; imgID = this.artistart && this.arr.length && p.lfm_img ? this.arr[ix] : image_path_o[i_x]; if (imgID_o != imgID) alpha = transLevel; else alpha = 255; timer.reset(timer.transition, timer.transitioni); timer.transition = window.SetInterval(function() {alpha = Math.min(alpha *= transIncr, 255); t.paint(); if (alpha == 255) timer.reset(timer.transition, timer.transitioni);}, 12);}
    this.on_playback_new_track = function() {counter = 0; men.counter = 0; if (!p.multi_new()) return; if (t.block()) {this.get = true; this.artist_reset();} else {if (this.artistart && p.lfm_img) {this.artist_reset(); this.grab_a_img();} else this.grab_f_img(); this.get = false;}}
    this.on_size = function() {if (p.text_only) {this.clear_c_rs_cache(); this.grab_f_img();} if (p.text_only && !ui.blur) return; this.img_c(); this.clear_a_rs_cache(); this.clear_c_rs_cache(); if (this.artistart) this.grab_a_img(); else this.grab_f_img(); init = false; if (p.img_only) p.get_multi(true); but.refresh(true);}
    this.rsImg = function() {core_img[i_x] = f_im[i_x].Clone(0, 0, f_im[i_x].Width, f_im[i_x].Height); xf = f_sz[i_x].x; yf = f_sz[i_x].y; rsimgL[i_x] = true; this.paint();}
    this.set_chk_arr = function(arr_ix) {chk_arr = [window.ID, arr_ix, this.displayed_other_panel]; window.NotifyOthers("chk_arr_jb", chk_arr);}
    this.setCrop = function(sz) {var imgRefresh = p.img_only || !p.text_only && !t.text; this.crop = this.artistart && (this.artCropImgOnly && imgRefresh || this.artCropDual && !p.img_only) || !this.artistart && (this.covCropImgOnly && imgRefresh || this.covCropDual && !p.img_only); p.setBorder(imgRefresh && this.crop, this.border); if (sz) {p.sizes(); if (ui.heading && !p.img_only) but.refresh();}}; if (p.img_only) this.setCrop(true);
    this.setReflStrength = function(n) {reflAlpha += n; reflAlpha = Math.max(Math.min(reflAlpha, 255), 0); window.SetProperty(" Image Reflection Setting (0-100)", "Strength," + Math.round(reflAlpha / 2.55) + ",Size," + reflSetup[3] + ",Gradient," + reflSetup[5]); if (refl_mask) refl_mask.Dispose(); refl_mask = false; this.bp = true; if (this.artistart && p.lfm_img) this.clear_a_rs_cache(); if (!p.art_ix && this.artistart || !p.alb_ix && !this.artistart) this.get_images(); else this.get_multi(p.art_ix);}
    var shuffle = function(ary) {for (var i = ary.length - 1; i >= 0; i--) {var randomIndex = Math.floor(Math.random() * (i + 1)), itemAtIndex = ary[randomIndex]; ary[randomIndex] = ary[i]; ary[i] = itemAtIndex;} return ary;}
    this.trace = function(x, y) {if (!p.autoEnlarge) return true; var arr = [], ex; if (this.artistart && p.lfm_img && this.arr.length) {arr = a_sz; ex = ix;} else {arr = f_sz; ex = i_x;} if (ex >= arr.length || !arr[ex]) return false; return x > arr[ex].x && x < arr[ex].x + arr[ex].w && y > arr[ex].y && y < arr[ex].y + arr[ex].h;}
	var toRGB = function(c) {return [c >> 16 & 0xff, c >> 8 & 0xff, c & 0xff];}
    var uniq = function(a) {var j = 0, len = a.length, out = [], seen = {}; for (var i = 0; i < len; i++) {var item = a[i]; if (seen[item] !== 1) {seen[item] = 1; out[j++] = item;}} return out;}
    this.wheel = function(step) {switch (utils.IsKeyPressed(0x10)){case false: if (this.arr.length < 2 || !this.artistart || p.text_only || !p.lfm_img) break; this.change(-step); if (this.artistart && p.cyc) timer.step = Math.floor(fb.PlaybackTime); break; case true: if (!p || (p.mul_item && but.btns["mt"] && but.btns["mt"].trace(p.m_x, p.m_y)) || p.text_trace || !this.reflection) break; this.setReflStrength(-step * 5); break;}}

    this.get_multi = function(n) {
        men.counter = 0; timer.men_step = 0;
        switch (true) {
            case this.artistart:
                if (p.text_only && !ui.blur) return; counter = 0; artist_o = artist; var stndBio = !n || n + 1 > p.artists.length; artist = !stndBio ? p.artists[n].name : name.artist(); var new_artist = artist && artist != artist_o || !artist; timer.step = 0;
                if (p.lfm_img) {if (new_artist) {folder = stndBio ? p.cleanPth(p.imgArtPth) : p.cleanMul(p.imgArtMul, artist, "", "", 1); folderSup = ""; if (!stndBio && p.supCache && !p.folder(folder)) folderSup = p.cleanMul(p.imgArtSup, artist, "", "", 1); this.clear_art_cache(); this.a_run = true; if (!this.arr.length) all_files_o_length = 0; ix = 0;} this.grab_a_img();}
                else this.grab_f_img(); this.get = false; break;
            case !this.artistart: t.mulAlbum = true; this.grab_f_img(); this.get = false; break;
        }
    }

    this.get_album_art_done = function(handle, art_id, image, image_path) {
        if (p.alb_ix && p.alb_ix < p.albums.length && !image && !this.artistart) { // !stndAlb + in lib + !image
            var a = p.albums[p.alb_ix].artist, l = p.albums[p.alb_ix].album, pe = [p.cleanMul(p.imgRevMul, a, l, "", 0)], fe = a.clean() + " - " + l.clean(); if (p.supCache) pe.push(p.cleanMul(p.imgRevSup, a, l, "", 0));
            for (var j = 0; j < pe.length; j++) for (var k = 0; k < ext.length; k++) {var ep = pe[j] + fe + ext[k]; if (p.file(ep)) {if (image_path_o[i_x] == ep && f_im[i_x] && !this.bp) return this.rsImg(); image_path_o[i_x] = ep; return cover_id = gdi.LoadImageAsync(window.ID, ep);}}
            if (fe != fe_done && p.rev_img) {var pth_cov = pe[!p.supCache ? 0 : 1], fn_cov = pth_cov + fe; if (p.server) serv.get_rev_img(a, l, pth_cov, fn_cov, false); else window.NotifyOthers("get_rev_img_jb", [a, l, pth_cov, fn_cov]); fe_done = fe;}
            return cover_id = gdi.LoadImageAsync(window.ID, "");
        }
        if (image_path_o[i_x] == image_path && f_im[i_x] && image && !this.bp) {return this.rsImg();} var origImg = image;
        if (!image && !this.artistart && !this.covType && !p.alb_ix) {
            var fe = name.alb_artist().clean() + " - " + name.album().clean(), pth_cov = [p.cleanPth(p.imgCovPth) + p.eval(p.imgCovFn).clean(), p.cleanMul(p.imgRevMul, name.alb_artist(), name.album(), "", 0) + fe];
            for (var j = 0; j < pth_cov.length; j++) for (var k = 0; k < ext.length; k++) {var ep = pth_cov[j] + ext[k]; if (p.file(ep)) {if (image_path_o[i_x] == ep && f_im[i_x] && !this.bp) return this.rsImg(); image_path_o[i_x] = ep; return cover_id = gdi.LoadImageAsync(window.ID, ep);}}
            if (image_path_o[i_x] == "stub" && f_im[i_x] && !this.bp) return this.rsImg();
            if (handle) {if (!p.file(userStubFile)) {
                var stubUser = utils.GetAlbumArtV2(handle, 0); if (stubUser) stubUser.SaveAs(userStubFile, "image/png");
                userStub = p.file(userStubFile) ? gdi.Image(userStubFile) : false;
            } if (userStub) {image = userStub; image_path_o[i_x] = "stub";}}
        }
        if (image_path_o[i_x] != "stub" || origImg) image_path_o[i_x] = image_path; if (!t.mulAlbum) this.clear_cov_cache(); core_img[i_x] = image;
        if (!core_img[i_x]) {core_img[i_x] = this.defStub(this.artistart ? 1 : 0);} if (!core_img[i_x]) return;
        this.img_c(); core_img[i_x] = this.img_rs("", f_im, i_x, core_img[i_x], f_sz, 0); this.paint();
    }

    this.grab_f_img = function() {
        var j = 0, k = 0; this.blurCheck(); i_x = this.artistart ? 0 : p.alb_ix + 1;
        if (p.alb_ix && p.alb_ix < p.albums.length && !this.artistart) { // !stndAlb
            var a = p.albums[p.alb_ix].artist, l = p.albums[p.alb_ix].album, metadb = lib.in_library(2, a, l);
            if (metadb) return utils.GetAlbumArtAsync(window.ID, metadb, 0, false); // check local
            else {
                var pe = [p.cleanMul(p.imgRevMul, a, l, "", 0)], fe = a.clean() + " - " + l.clean(); if (p.supCache) pe.push(p.cleanMul(p.imgRevSup, a, l, "", 0));
                for (j = 0; j < pe.length; j++) for (k = 0; k < ext.length; k++) {var ep = pe[j] + fe + ext[k]; if (p.file(ep)) {if (image_path_o[i_x] == ep && f_im[i_x] && !this.bp) return this.rsImg(); image_path_o[i_x] = ep; return cover_id = gdi.LoadImageAsync(window.ID, ep);}}
                if (fe != fe_done && p.rev_img) {var pth_cov = pe[!p.supCache ? 0 : 1], fn_cov = pth_cov + fe; if (p.server) serv.get_rev_img(a, l, pth_cov, fn_cov, false); else window.NotifyOthers("get_rev_img_jb", [a, l, pth_cov, fn_cov]); fe_done = fe;}
                return cover_id = gdi.LoadImageAsync(window.ID, "");
            }
        } // stndAlb
        if (!p.alb_ix && p.extra && !this.artistart && !this.covType) {for (j = 0; j < p.extraPaths.length; j++) for (k = 0; k < ext.length; k++) {var ep = p.eval(p.extraPaths[j] + ext[k]); if (p.file(ep)) {if (image_path_o[i_x] == ep && f_im[i_x] && !this.bp) return this.rsImg(); image_path_o[i_x] = ep; return cover_id = gdi.LoadImageAsync(window.ID, ep);}}}
        var handle = p.handle(p.focus);
        if (handle) return utils.GetAlbumArtAsync(window.ID, handle, this.artistart ? 4 : this.covType, !this.covType && !this.artistart ? false: true);
        if (fb.IsPlaying && handle) return; if (image_path_o[i_x] == "noitem" && f_im[i_x] && !this.bp) return this.rsImg();
        core_img[i_x] = this.defStub(this.artistart ? 1 : 0); if (!core_img[i_x]) return; image_path_o[i_x] = "noitem"; this.img_c(); core_img[i_x] = this.img_rs("", f_im, i_x, core_img[i_x], f_sz, 0); this.paint();
    }

    this.read_arr = function() {
        var all_files = utils.Glob(folder + "*").toArray();
        if (!all_files.length && folderSup) all_files = utils.Glob(folderSup + "*").toArray();
        if (all_files.length == all_files_o_length) return; var j = 0, incl_lge = 0, newArr = false; // incl_lge 0 & 1 - exclude & include artist images > 8 MB
        if (!this.arr.length) {newArr = true; for (j = 0; j < a_im.length; j++) {rsimgA[j] = false; if (a_im[j]) a_im[j].Dispose(); a_im = [];} for (j = 0; j < a_img.length; j++)  if (a_img[j]) a_img[j].Dispose(); a_img = [];}
        all_files_o_length = all_files.length;
        for (j = 0; j < all_files.length; j++) {
            if (!p.file(all_files[j]) || p.fs.GetFile(all_files[j]).Size >= 8388608 && !incl_lge) continue;
            if ((/_([a-z0-9]){32}\.jpg$/).test(p.fs.GetFileName(all_files[j])) || (/(?:jpe?g|gif|png|bmp)$/i).test(p.fs.GetExtensionName(all_files[j])) && !(/ - /).test(p.fs.GetBaseName(all_files[j]))) {
                var bAdd = true; if (bAdd) for (var h = 0; h < exclArr.length; h++) if (p.fs.GetFile(all_files[j]).Size == exclArr[h]) {bAdd = false; break;}
                if (bAdd) this.arr.push(all_files[j]);}}
        if (this.arr.length > 1) this.arr = uniq(this.arr); if (newArr && this.arr.length > 1) this.arr = shuffle(this.arr);
    }

    this.artist_image = function() {
        if (this.arr.length > 0 && p.lfm_img) {
            if (a_im[ix]) {artist_img = a_im[ix]; xa = a_sz[ix].x; ya = a_sz[ix].y; rsimgA[ix] = true; this.paint();} else if (a_img[ix]) {artist_img = a_img[ix]; this.img_c(); artist_img = this.img_rs(a_img, a_im, ix, artist_img, a_sz, 1); this.paint();}
            else g_valid_tid = gdi.LoadImageAsync(window.ID, this.arr[ix]);
        } else if (!init) this.grab_f_img();
    }

    this.load_done = function(tid, image) {
        if (cover_id == tid) {
            if (!t.mulAlbum) this.clear_cov_cache(); core_img[i_x] = image;
            if (!core_img[i_x]) core_img[i_x] = this.defStub(0); if (!core_img[i_x]) return;
            this.img_c(); core_img[i_x] = this.img_rs("", f_im, i_x, core_img[i_x], f_sz, 0); this.paint();
        }
        if (g_valid_tid != tid) return;
        artist_img = image; if (!artist_img) {this.arr.splice(ix, 1); if (this.arr.length > 1) this.change(1); return;}
        this.img_c(); artist_img = this.img_rs(a_img, a_im, ix, artist_img, a_sz, 1); this.paint();
    }

    this.img_c = function() {
        if (!p.img_only && t.text && this.autoAlign && p.style < 4) {if (p.style == 0 || p.style == 2) {p.img_l = p.text_l; p.img_r = p.text_r;} if (p.style == 1 || p.style == 3) {p.img_t = Math.round(p.text_t - ui.heading_h + ui.font_h / 4.1); p.img_b = Math.round(p.h - (p.text_t + p.lines_drawn * ui.font_h - ui.font_h / 12.5 - ui.textPad));}}
        x_l = !t.text ? p.bor_l : p.img_l; x_r = !t.text ? p.bor_r : p.img_r; y_t = !t.text ? p.bor_t : p.img_t; y_b = !t.text ? p.bor_b : p.img_b;
        nw = !p.style || p.style == 2 || p.style > 3 && t.text ? p.w - p.img_l - p.img_r : !p.img_only && t.text ? p.imgs : p.w - x_l - x_r;
        this.nh = p.style == 1 || p.style == 3 || p.style > 3 && t.text && !this.alignAuto ? p.h - p.img_t - p.img_b : !p.img_only && t.text ? p.imgs : p.h - y_t - y_b;
        if (this.border == 1 || this.border == 3) {var i_sz = Math.max(Math.min(this.nh, nw), 0); bor_w1 = !i_sz ? 5 * ui.scale : i_sz > 250 ? 5 * ui.scale : Math.ceil(5 * ui.scale * i_sz / 250);} else bor_w1 = 0; bor_w2 = bor_w1 * 2;
        nw = Math.max(nw - bor_w2, p.style < 4 ? 10 : 0); this.nh = Math.max(this.nh - bor_w2, p.style < 4 ? 10 : 0);
    }

    this.img_rs = function(p_img, p_im, i, image, o_sz, n) {
        try {
            if (!image) return;
            var imgx = 0, imgy = 0, imgw = image.Width, imgh = image.Height, tw = 0, th = 0;
            switch (true) {
                case !this.crop:
                    if (p.style < 4 || !this.alignAuto || !t.text || p.img_only) {var s = Math.min(this.nh / image.Height, nw / image.Width); tw = Math.round(image.Width * s); th = Math.round(image.Height * s);}
                    else {
                        var s1 = image.Width / image.Height, s2 = this.nh > 0 ? nw / this.nh : Infinity;
                        if (s1 > s2) {var s = Math.min(this.nh / image.Height, nw / image.Width); tw = Math.round(image.Width * s); th = Math.round(image.Height * s); y_t = Math.round((this.nh - th) / 2 + y_t);}
                        else {y_t = p.img_t; this.nh = p.h - p.img_t - p.img_b - bor_w2; var s = Math.min(this.nh / image.Height, nw / image.Width); tw = Math.round(image.Width * s); th = Math.round(image.Height * s);}
                    }
                    break;
                case this.crop:
                    if (p.style > 3 && t.text) this.nh = p.h - p.img_t - p.img_b - bor_w2;
                    var s1 = image.Width / nw, s2 = image.Height / this.nh;
                    if (!this.artistart && Math.abs(s1 / s2 - 1) < 0.05) {imgx= 0; imgy = 0; imgw = image.Width; imgh = image.Height; tw = Math.round(nw); th = Math.round(this.nh);}
                    else {if (s1 > s2) {imgw = Math.round(nw * s2); imgh = image.Height; imgx = Math.round((image.Width - imgw) / 2); imgy = 0; tw = Math.round(nw); th = Math.round(this.nh);} else {imgw = image.Width; imgh = Math.round(this.nh * s1); imgx = 0; imgy = Math.round((image.Height - imgh) / 8); tw = Math.round(nw); th = Math.round(this.nh);}} break;
            }
            if ((p.style == 0 || p.style == 2 || p.style > 3) && !p.img_only && t.text && this.alignH != 1) {if (this.alignH == 2) x_l = Math.round(p.w - p.img_r - tw - bor_w2);} else x_l = Math.round((nw - tw) / 2 + x_l);
            if ((p.style == 1 || p.style == 3 || p.style > 3 && !this.alignAuto) && !p.img_only && t.text && this.alignV != 1) {if (this.alignV == 2) y_t = Math.round(p.h - p.img_b - th - bor_w2);} else if (p.style < 4 || !this.alignAuto || !t.text || p.img_only) y_t = Math.round((this.nh - th) / 2 + y_t);
            var tx = x_l, ty = y_t;
            switch (n) {case 0: xf = tx; yf = ty; break; case 1: xa = tx; ya = ty; p_img[i] = image; break;} o_sz[i] = {"x": tx, "y": ty, "w": tw, "h": th}; imgb = 0; 
            switch (this.border) {
                case 0:
                    p_im[i] = image.Clone(imgx, imgy, imgw, imgh); p_im[i] = p_im[i].Resize(tw, th, 2); 
                    if (!ui.overlayStyle && p.style > 3 && t.text && !p.img_only) p_im[i] = this.fade_img(p_im[i], tx, ty, tw, th);
                    if (this.reflection) {p_im[i] = this.refl_img(p_im[i], i, tx, ty, tw, th, o_sz); tx = o_sz[i].x; ty = o_sz[i].y;}
                    if (ui.blur && p_im[i] && !(p.img_only && this.crop)) {
                        if (!this.smoothTrans) p_im[i] = this.blur_img(image, p_im[i], tx, ty, p_im[i].Width, p_im[i].Height);
                        else {if (n) b_aim[i] = this.blur_img(image, p_im[i], tx, ty, p_im[i].Width, p_im[i].Height); else b_fim[i] = this.blur_img(image, p_im[i], tx, ty, p_im[i].Width, p_im[i].Height);}
                    }
                    if (n) rsimgA[ix] = true; else rsimgL[i_x] = true; return p_im[i];
                default:
                    p_im[i] = image.Clone(0, 0, image.Width, image.Height); if (this.crop) image = image.Clone(imgx, imgy, imgw, imgh);
                    if (this.border > 1 && !this.reflection) {var imgo = 7,  dpiCorr = (ui.scale - 1) * imgo, imb = imgo - dpiCorr; imgb = 15 + dpiCorr; var imgo = 7, imb = imgo - dpiCorr; sh_img = gdi.CreateImage(Math.floor(tw + bor_w2 + imb), Math.floor(th + bor_w2 + imb)); var gb = sh_img.GetGraphics(); gb.FillSolidRect(imgo, imgo, tw + bor_w2 - imgb, th + bor_w2 - imgb, RGB(0, 0, 0)); sh_img.ReleaseGraphics(gb); sh_img.StackBlur(12);}
                    var bor_img = gdi.CreateImage(Math.floor(tw + bor_w2 + imgb), Math.floor(th + bor_w2 + imgb)); var gb = bor_img.GetGraphics();
                    if (this.border > 1 && !this.reflection) gb.DrawImage(sh_img, 0, 0, Math.floor(tw + bor_w2 + imgb), Math.floor(th + bor_w2 + imgb), 0, 0, sh_img.Width, sh_img.Height);
                    if (this.border == 1 || this.border == 3) gb.FillSolidRect(0, 0, tw + bor_w2, th + bor_w2, RGB(255, 255, 255)); image = image.Resize(tw, th, 2);
                    gb.DrawImage(image, bor_w1, bor_w1, image.Width, image.Height, 0, 0, image.Width, image.Height);
                    bor_img.ReleaseGraphics(gb); if (sh_img) sh_img.Dispose(); sh_img = false;
                    if (!ui.overlayStyle && p.style > 3 && t.text && !p.img_only) bor_img = this.fade_img(bor_img, tx, ty, bor_img.Width, bor_img.Height);
                    if (this.reflection) {bor_img = this.refl_img(bor_img, i, tx, ty, bor_img.Width, bor_img.Height, o_sz); tx = o_sz[i].x; ty = o_sz[i].y; }
                    if (ui.blur && bor_img && !(p.img_only && this.crop && this.border < 2)) {
                        if (!this.smoothTrans) bor_img = this.blur_img(p_im[i], bor_img, tx, ty, bor_img.Width, bor_img.Height);
                        else {if (n) b_aim[i] = this.blur_img(p_im[i], bor_img, tx, ty, bor_img.Width, bor_img.Height); else b_fim[i] = this.blur_img(p_im[i], bor_img, tx, ty, bor_img.Width, bor_img.Height);}
                    }
                    p_im[i] = bor_img; if (n) rsimgA[ix] = true; else rsimgL[i_x] = true; return bor_img;
        }} catch (e) {}
    }

    this.blur_img = function(image, im, x, y, w, h) {
        if (!image || !im || !p.w || !p.h) return;
        if (covBlur && ui.blur && (this.artistart || p.text_only || p.alb_ix) && new_BlurAlb) {
            if (f_blur) f_blur.Dispose(); f_blur = false;
            if (p.extra && !this.covType) for (var j = 0; j < p.extraPaths.length; j++) for (var k = 0; k < ext.length; k++) {var ep = p.eval(p.extraPaths[j] + ext[k]); if (p.file(ep)) {f_blur = gdi.Image(ep); k = ext.length; j = p.extraPaths.length;}}
            if (!f_blur) {var handle = p.handle(p.focus); if (handle) f_blur = utils.GetAlbumArtV2(handle, this.covType, !this.covType ? false: true);}
            if (!f_blur && !this.covType) {var pth_cov = p.cleanPth(p.imgCovPth) + p.eval(p.imgCovFn).clean(); for (var k = 0; k < ext.length; k++) {var ep = pth_cov + ext[k]; if (p.file(ep)) {f_blur = gdi.Image(ep); k = ext.length;}}}
            if (!f_blur && !this.covType) if (handle) f_blur = utils.GetAlbumArtV2(handle, 0); if (!f_blur) f_blur = this.noimg[0].Clone(0, 0, this.noimg[0].Width, this.noimg[0].Height); new_BlurAlb = false; if (f_blur) f_blur = f_blur.Resize(p.w, p.h);
        }
        if (covBlur && ui.blur && (this.artistart || p.text_only || p.alb_ix) && f_blur) image = f_blur;
        var i = gdi.CreateImage(p.w, p.h), g = i.GetGraphics(); g.SetInterpolationMode(0);
        if (blurAutofill) {var s1 = image.Width / p.w, s2 = image.Height / p.h; if (s1 > s2) {var imgw = Math.round(p.w * s2), imgh = image.Height, imgx = Math.round((image.Width - imgw) / 2), imgy = 0;} else {var imgw = image.Width, imgh = Math.round(p.h * s1), imgx = 0, imgy = Math.round((image.Height - imgh) / 8);} image = image.Clone(imgx, imgy, imgw, imgh);}
        if (ui.blur_blend) {
            var iSmall = image.Resize(p.w * ui.blurLevel / 100, p.h * ui.blurLevel / 100, 2), iFull = iSmall.resize(p.w, p.h, 2), offset = 90 - ui.blurLevel;
            g.DrawImage(iFull, 0 - offset, 0 - offset, p.w + offset * 2, p.h + offset * 2, 0, 0, iFull.Width, iFull.Height, 0, 63 * ui.blurAlpha);
        } else {
            g.DrawImage(image, 0, 0, p.w, p.h, 0, 0, image.Width, image.Height); if (ui.blurLevel > 1) i.StackBlur(ui.blurLevel);
			var colorSchemeArray = JSON.parse(i.GetColourSchemeJSON(15)), rTot = 0, gTot = 0, bTot = 0, freqTot = 0;
			for (var j = 0; j < colorSchemeArray.length; j++) {var col = toRGB(colorSchemeArray[j].col), freq = colorSchemeArray[j].freq; rTot += Math.pow(col[0], 2) * freq; gTot += Math.pow(col[1], 2) * freq; bTot += Math.pow(col[2], 2) * freq; freqTot += freq;}
			var avgCol = [clamp(Math.round(Math.sqrt(rTot / freqTot)), 0 , 255), clamp(Math.round(Math.sqrt(gTot / freqTot)), 0 , 255), clamp(Math.round(Math.sqrt(gTot / freqTot)), 0 , 255)];
			var lightCover = ui.get_textselcol(avgCol, true, true) == 50 ? true : false;
            g.FillSolidRect(0, 0, p.w, p.h, lightCover ? ui.bg_color_light : ui.bg_color_dark);
        }
        if (!p.text_only && !this.smoothTrans) g.DrawImage(im, x, y, w, h, 0, 0, im.Width, im.Height); i.ReleaseGraphics(g); return i;
    }

    this.fade_img = function(image, x, y, w, h) {
        var xl = Math.max(0, p.tBoxL - x), f = Math.min(w, p.tBoxL - x + p.tBoxW); this.bp = false; if (xl >= f) return image; var wl = f - xl, yl = Math.max(0, p.tBoxT - y); f = Math.min(h, p.tBoxT - y + p.tBoxH); if (yl >= f) return image; var hl = f - yl;
        if (!fade_mask || this.resetFade) {fade_mask = gdi.CreateImage(500, 500), gb = fade_mask.GetGraphics(), km = ui.fadeSlope != -1 && p.img_t <= p.text_t -ui.heading_h ? ui.fadeAlpha / 500 + ui.fadeSlope  / 10 : 0; for (var k = 0; k < 500; k++) {var c = 255 - Math.min(Math.max(ui.fadeAlpha - k * km, 0), 255); gb.FillSolidRect(0, k, 500, 1, RGB(c, c, c));} fade_mask.ReleaseGraphics(gb); this.resetFade = false;}
        var fade = image.Clone(0, 0, image.Width, image.Height), f_mask = fade_mask.Clone(0, 0, fade_mask.Width, fade_mask.Height); 
        var fadeI = gdi.CreateImage(w, h), gb = fadeI.GetGraphics(); gb.DrawImage(f_mask, xl, yl, wl, hl, 0, 0, f_mask.Width, f_mask.Height);
        fadeI.ReleaseGraphics(gb); fade.ApplyMask(fadeI); if (f_mask) f_mask.Dispose(); if (fadeI) fadeI.Dispose(); return fade;
    }

    this.refl_img = function(image, i, x, y, w, h, o_sz) {
        if (!refl_mask) {refl_mask = gdi.CreateImage(500, 500), gb = refl_mask.GetGraphics(), km = reflSlope != -1 ? reflAlpha / 500 + reflSlope  / 10 : 0; for (var k = 0; k < 500; k++) {var c = 255 - Math.min(Math.max(reflAlpha - k * km, 0), 255); gb.FillSolidRect(0, k, 500, 1, RGB(c, c, c));} refl_mask.ReleaseGraphics(gb);}
        if (!this.reflectionType) {switch (p.style) {case 0: case 2: sw = this.alignH == 1 ? p.style : this.alignH == 0 ? 3 : 1; break; case 1: case 3: sw = this.alignV == 1 ? p.style : this.alignV == 0 ? 0 : 2; break; default: sw = this.alignH == 1 ? 0 : 3 - this.alignH; break;}} else sw = [2, 1, 0, 3][this.reflectionType - 1]; this.bp = false;
        switch (sw) {
            case 0: var ref_sz = Math.round(Math.min(p.h - y - h, image.Height * reflSz)); if (ref_sz <= 0) return image; var refl = image.Clone(0, image.Height - ref_sz, image.Width, ref_sz), r_mask = refl_mask.Clone(0, 0, refl_mask.Width, refl_mask.Height); if (refl) {r_mask = r_mask.Resize(refl.Width, refl.Height); refl.RotateFlip(6); refl.ApplyMask(r_mask);} var reflImg = gdi.CreateImage(w, h + ref_sz), gb = reflImg.GetGraphics(); gb.DrawImage(image, 0, 0, w, h, 0, 0, w, h); gb.DrawImage(refl, 0, h, w, h, 0, 0, w, h); o_sz[i].h = h + ref_sz; reflImg.ReleaseGraphics(gb); break;
            case 1: var ref_sz = Math.round(Math.min(x, image.Width * reflSz)); if (ref_sz <= 0) return image; var refl = image.Clone(0, 0, ref_sz, image.Height), r_mask = refl_mask.Clone(0, 0, refl_mask.Width, refl_mask.Height); r_mask.RotateFlip(1); if (refl) {r_mask = r_mask.Resize(refl.Width, refl.Height); refl.RotateFlip(4); refl.ApplyMask(r_mask);} var reflImg = gdi.CreateImage(ref_sz + w, h), gb = reflImg.GetGraphics(); gb.DrawImage(image, ref_sz, 0, w, h, 0, 0, w, h); gb.DrawImage(refl, 0, 0, ref_sz, h, 0, 0, ref_sz, h); if (this.artistart) xa = x - ref_sz; else xf = x - ref_sz; o_sz[i].x = x - ref_sz; o_sz[i].w = w + ref_sz; reflImg.ReleaseGraphics(gb); break;
            case 2: var ref_sz = Math.round(Math.min(y, image.Height * reflSz)); if (ref_sz <= 0) return image; var refl = image.Clone(0, 0, image.Width, ref_sz), r_mask = refl_mask.Clone(0, 0, refl_mask.Width, refl_mask.Height); r_mask.RotateFlip(2); if (refl) {r_mask = r_mask.Resize(refl.Width, refl.Height); refl.RotateFlip(6); refl.ApplyMask(r_mask);} var reflImg = gdi.CreateImage(w, ref_sz + h), gb = reflImg.GetGraphics(); gb.DrawImage(image, 0, ref_sz, w, h, 0, 0, w, h); gb.DrawImage(refl, 0, 0, w, ref_sz, 0, 0, w, ref_sz); if (this.artistart) ya = y  - ref_sz; else yf = y - ref_sz; o_sz[i].y = y - ref_sz; o_sz[i].h = ref_sz + h; reflImg.ReleaseGraphics(gb); break;
            case 3: var ref_sz = Math.round(Math.min(p.w - x - w, image.Width * reflSz)); if (ref_sz <= 0) return image; var refl = image.Clone(image.Width - ref_sz, 0, ref_sz, image.Height), r_mask = refl_mask.Clone(0, 0, refl_mask.Width, refl_mask.Height); r_mask.RotateFlip(3); if (refl) {r_mask = r_mask.Resize(refl.Width, refl.Height); refl.RotateFlip(4); refl.ApplyMask(r_mask);} var reflImg = gdi.CreateImage(w + ref_sz, h), gb = reflImg.GetGraphics(); gb.DrawImage(image, 0, 0, w, h, 0, 0, w, h); gb.DrawImage(refl, w, 0, ref_sz, h, 0, 0, ref_sz, h); o_sz[i].w = w + ref_sz; reflImg.ReleaseGraphics(gb); break;
        } if (r_mask) r_mask.Dispose(); if (refl) refl.Dispose(); return reflImg;
    }

    this.draw = function(gr) {
        if (p.text_only && !ui.blur) return; this.get_img_fallback();
        try {var artArr = this.artistart && p.lfm_img && this.arr.length;
        if (artArr && !rsimgA[ix]) return; if (!artArr && !rsimgL[i_x]) return;
        var pic = artArr ? artist_img : core_img[i_x]; if (!pic) return;
        if (ui.blur && this.smoothTrans) {var arr = artArr ? b_aim : b_fim, ex = artArr ? ix : i_x; if (arr[ex]) gr.DrawImage(arr[ex], 0, 0, arr[ex].Width, arr[ex].Height, 0, 0, arr[ex].Width, arr[ex].Height);}
        if (ui.blur && !this.smoothTrans) gr.DrawImage(pic, 0, 0, pic.Width, pic.Height, 0, 0, pic.Width, pic.Height, 0, alpha);
        else if (!p.text_only) {if (artArr) gr.DrawImage(pic, xa, ya, pic.Width, pic.Height, 0, 0, pic.Width, pic.Height, 0, alpha); else gr.DrawImage(pic, xf, yf, pic.Width, pic.Height, 0, 0, pic.Width, pic.Height, 0, alpha);}} catch (e) {}
    }
} 
var img = new image_manager();

function timers() {
    var counter = 0, timer_arr = ["dl", "focus", "img", "sim1", "sim2", "source", "transition", "zSearch"]; this.step = 0; this.men_step = 0;
    for (var i = 0; i < timer_arr.length; i++) {this[timer_arr[i]] = false; this[timer_arr[i] + "i"] = i;}
    var res = function(force, reset) {window.NotifyOthers("grab_img_jb", force); if (p.server) img.grab(force); if (reset) timer.reset(timer.dl, timer.dli);}
    this.reset = function(timer, n) {if (timer) window.ClearTimeout(timer); this[timer_arr[n]] = false;}
    this.decelerating = function(force) {counter = 0; this.reset(this.dl, this.dli); this.dl = window.SetInterval(function() {counter++; res(force, counter < 5 ? false : true); if (counter > 4) timer.dl = window.SetTimeout(function() {res(force); timer.dl = window.SetTimeout(function() {res(force); timer.dl = window.SetTimeout(function() {res(force); timer.dl = window.SetTimeout(function() {res(force); timer.dl = window.SetTimeout(function() {res(force); timer.dl = false;}, 7000)}, 6000)}, 5000)}, 4000)}, 2000)}, 1000);}
    this.image = function() {if (!p.server) return; this.reset(this.img, this.imgi); this.img = window.SetInterval(function() {img.fresh(); men.fresh(); window.NotifyOthers("img_chg_jb", 0);}, 1000);}
}
var timer = new timers(); timer.image();

function on_focus(is_focused) {if (is_focused) t.focus = is_focused;}
function on_get_album_art_done(handle, art_id, image, image_path) {img.get_album_art_done(handle, art_id, image, image_path);}
function on_item_focus_change() {if (fb.IsPlaying && !p.focus) return; if (p.mul_item) p.get_multi(true); else if (!p.multi_new()) return; if (t.block() && !p.server) {img.get = true; t.get = p.focus ? 2 : 1; img.artist_reset(); t.album_reset(); t.artist_reset();} else {if (t.block() && p.server) {img.get = true; t.get = 1; img.artist_reset(); t.album_reset(); t.artist_reset();} else {img.get = false; t.get = 0;} p.focus_changed(250); p.item_changed(p.focus, 1000);}}
function on_key_down(vkey) {switch(vkey) {case 0x10: case 0x11: case 0x12: t.paint(); break; case 0x21: if (!p.img_only && !ui.zoom()) t.scrollbar_type().wheel(1, true); break; case 0x22: if (!p.img_only && !ui.zoom()) t.scrollbar_type().wheel(-1, true); break; case 37: img.wheel(1); break; case 39: img.wheel(-1); break;}}
function on_key_up(vkey) {if (vkey == 0x10 || vkey == 0x11 || vkey == 0x12) t.paint();}
function on_library_items_added() {if (!lib) return; lib.update = true;}; function on_library_items_removed() {if (!lib) return; lib.update = true;}; function on_library_items_changed() {if (!lib) return; lib.update = true;}
function on_load_image_done(tid, image) {img.load_done(tid, image);}
function on_metadb_changed() {if (p.ir() || t.block() && !p.server || !p.multi_new()) return; p.get_multi(true); if (!p.img_only) t.on_playback_new_track(); if (!p.text_only || ui.blur) img.on_playback_new_track(); p.item_changed(p.focus, 500);}
function on_notify_data(name, info) {if (ui.local) on_cui_notify(name, info); switch(name) {case "img_chg_jb": img.fresh(); men.fresh(); break; case "chk_arr_jb": img.chk_arr(info); break; case "custom_style_jb": p.on_notify(info); break; case "force_update_jb": if (p.server) serv.fetch(1, info[0], info[1]); break; case "get_multi_jb": p.get_multi(false); break; case "get_rev_img_jb": if (p.server) serv.get_rev_img(info[0], info[1], info[2], info[3], false); break; case "grab_img_jb": img.grab(info); break; case "grab_txt_jb": t.grab(); break; case "multi_tag_jb": if (p.server) serv.fetch(false, info[0], info[1]); break; case "new_lang_jb": window.Reload(); break; case "not_server_jb": p.server = false; timer.reset(timer.img, timer.imgi); timer.reset(timer.zSearch, timer.zSearchi); break; case "script_unload_jb": p.server = true; window.NotifyOthers("not_server_jb", 0); break; case "reload_jb": if (!p.art_ix && img.artistart || !p.alb_ix && !img.artistart) window.Reload(); else {t.artistFlush(); t.albumFlush(); t.grab(); if (p.text_only) t.paint();} break;}}
function on_paint(gr) {ui.draw(gr); img.draw(gr); t.draw(gr); t.j_draw(gr); but.draw(gr); t.drawEd(gr); ui.lines(gr);}
function on_playback_new_track() {if (p.server) serv.fetch(false, [0, false], [0, false]); if (p.focus) return; t.on_playback_new_track(); img.on_playback_new_track();}
function on_playback_dynamic_info_track() {if (p.server) serv.fetch_dynamic(); t.on_playback_new_track(); img.on_playback_new_track();}
function on_playback_stop(reason) {if (reason == 2) return; on_item_focus_change();}
function on_playlists_changed() {men.playlists_changed();}
function on_playlist_items_added(pn) {if (pn == plman.ActivePlaylist) p.upd_handle_list = true; on_item_focus_change();}
function on_playlist_items_removed(pn) {if (pn == plman.ActivePlaylist) p.upd_handle_list = true; on_item_focus_change();}
function on_playlist_items_reordered(pn) {if (pn == plman.ActivePlaylist) p.upd_handle_list = true;}
function on_playlist_switch() {p.upd_handle_list = true; on_item_focus_change();}
function on_mouse_lbtn_dblclk(x, y) {but.lbtn_dn(x, y); if (!p.dbl_click) return; p.click(x, y);}
function on_mouse_lbtn_down(x, y) {but.lbtn_dn(x, y); t.scrollbar_type().lbtn_dn(x, y); tb.lbtn_dn(x, y); if (p.dbl_click) return; p.click(x, y);}
function on_mouse_lbtn_up(x, y) {t.scrollbar_type().lbtn_up(x, y); tb.lbtn_up(x, y); but.lbtn_up(x, y);}
function on_mouse_leave() {p.leave(); but.leave(); t.scrollbar_type().leave(); p.m_y = -1;}
function on_mouse_mbtn_down(x, y) {p.mbtn_dn(x, y);}
function on_mouse_move(x, y) {if (p.m_x == x && p.m_y == y) return; p.move(x, y); but.move(x, y); t.scrollbar_type().move(x, y); tb.img_move(x, y); tb.move(x, y); p.m_x = x; p.m_y = y;}
function on_mouse_rbtn_up(x, y) {men.rbtn_up(x, y); return true;}
function on_mouse_wheel(step) {switch (ui.zoom()) {case false: if (but.btns["mt"] && but.btns["mt"].trace(p.m_x, p.m_y)) men.wheel(step, false, false); else if (p.text_trace) {if (!p.img_only) t.scrollbar_type().wheel(step, false);} else {img.wheel(step); if (p.mul_item) men.wheel(step, false, true);} break; default: if (ui.zoom()) ui.wheel(step); if (utils.IsKeyPressed(0x11)) but.wheel(step); if (utils.IsKeyPressed(0x10)) {if (!p.text_trace) img.wheel(step); if (but.btns["mt"] && but.btns["mt"].trace(p.m_x, p.m_y)) men.wheel(step, false, false);} break;}}
function on_script_unload() {if (p.server) {window.NotifyOthers("script_unload_jb", 0); timer.reset(timer.img, timer.imgi);} but.on_script_unload();}
function on_size() {t.rp = false; p.w = window.Width; p.h = window.Height; if (!p.w || !p.h) return; ui.get_font(); t.on_size(); img.on_size(); t.rp = true; img.displayed_other_panel = null;}
function RGB(r, g, b) {return 0xff000000 | r << 16 | g << 8 | b;}
function RGBA(r, g, b, a) {return a << 24 | r << 16 | g << 8 | b;}
function StringFormat() {var a = arguments, h_align = 0, v_align = 0, trimming = 0, flags = 0; switch (a.length) {case 3: trimming = a[2]; case 2: v_align = a[1]; case 1: h_align = a[0]; break; default: return 0;} return (h_align << 28 | v_align << 24 | trimming << 20 | flags);}
    
function server() {
    if (!Date.now) {Date.now = function now(){return new Date().getTime();}}
    String.prototype.format = function() {return this.replace(/<P><\/P>/gi, "").replace(/<p[^>]*>/gi, "").replace(/\r/g, "").replace(/\n/g, "").replace(/<\/p>/gi, "\r\n\r\n").replace(/<br>/gi, "\r\n").replace(/(<([^>]+)>)/ig, '').replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&quot/g, '"').replace(/&nbsp;/g, "").replace(/^ +/gm, "").replace(/^\s+|\s+$/g, "");}
    String.prototype.tidy = function() {return this.replace(/\band\b|\//gi, "&").replace(/[\.,\!\?\:;'\u2019"\-_\(\)\[\]\u2010\s+]/g, "").replace(/\$/g, "s").toLowerCase();}

    var albm = "", album = "", alb_artist = "", alb_id = "", album_id = "", artist = "", auto_corr = 1, ext = [".jpg", ".png", ".gif", ".bmp", ".jpeg"];
    var bioCacheSave = function(n) {if (!Array.isArray(imgToDelete)) {imgToDelete = []; n = true;} if (n) p.save(bioCache, JSON.stringify(imgToDelete, null, 3));}
    var bioCache = fb.ProfilePath + "yttm\\" + "cache_bio.json", imgToDelete = []; if (p.file(bioCache)) imgToDelete = p.json_parse(utils.ReadTextFile(bioCache)); bioCacheSave();
    if (p.server) {var dn_arr = ["am_bio", "lfm_bio", "am_rev", "lfm_rev", "dl_art_img", "lfm_cov"]; 
    for (var i = 0; i < dn_arr.length; i++) {if (i < dn_arr.length - 1) this[dn_arr[i]] = parseFloat(utils.ReadINI(p.bio_ini, "AUTO-FETCH", p.def_dn[i].name)); else this[dn_arr[i]] = parseFloat(utils.ReadINI(p.bio_ini, "COVERS: MUSIC FILES", p.cov[0].name)); if (this[dn_arr[i]] !== 1 && this[dn_arr[i]] !== 0) this[dn_arr[i]] = i < dn_arr.length - 1 ? p.def_dn[i].dn : p.cov[0].path;}}
    var auto_add = parseFloat(utils.ReadINI(p.bio_ini, "MISCELLANEOUS", p.def_tf[6].name)); if (auto_add !== 1 && auto_add !== 0) auto_add = p.def_tf[6].tf; var exp = Math.max(p.d * utils.ReadINI(p.bio_ini, "MISCELLANEOUS", p.def_tf[4].name) / 28, p.d), upd = p.d / 28; if (!exp || isNaN(exp)) exp = p.d;
    var imgNo = parseFloat(utils.ReadINI(p.bio_ini, "MISCELLANEOUS", p.def_tf[5].name)); if (!imgNo && imgNo !== 0 || isNaN(imgNo)) imgNo = p.def_tf[5].tf; imgNo = Math.min(20, imgNo);
    var artLimit = parseFloat(utils.ReadINI(p.bio_ini, "MISCELLANEOUS", p.def_tf[7].name)); artLimit = artLimit ? Math.max(artLimit, imgNo) : 0; if (artLimit && !window.GetProperty("SYSTEM.Cache Limit Advisory", false)) {var f_pth = p.cleanPth(p.imgArtPth, name.artist(p.focus)); f_pth = f_pth ? f_pth : "N/A"; fb.ShowPopupMessage("Artist image cache limit: now enabled. This is a BETA feature.\r\n\r\nLimits number of images stored per artist to value set. If used with auto-add, newer images are added & older removed to give a fixed number of up-to-date images.\r\n\r\nOnly considers images ending in \"_32-alphanumeric-string.jpg\", e.g. Coldplay_421cac7d8e42662f069c4b69e7934d7b.jpg.\r\n\r\nIf a custom save location is used, ensure images are saving where expected & there aren't other matching images.\r\n\r\nCurrent save folder: " + f_pth + "\r\n\r\nThe cache limit is applied following image update and when images are no longer in use.", "Biography"); window.SetProperty("SYSTEM.Cache Limit Advisory", true);}
    var bio_json = fb.ProfilePath + "yttm\\" + "update_bio.json"; try {if (!p.file(bio_json)) p.save(bio_json, JSON.stringify([{"name":"update", "time":Date.now()}], null, 3)); var m = p.json_parse(utils.ReadTextFile(bio_json)); if (m[0].name != "update") {m.unshift({"name":"update", "time":Date.now()}); p.save(bio_json, JSON.stringify(m, null, 3))}} catch (e) {}

    var done = function(f, exp) {try {if (!p.file(bio_json)) return false; var m = p.json_parse(utils.ReadTextFile(bio_json)); var k = m.length, n = Date.now(), r = n - exp, u = n - upd; if (m.length && m[0].time < u) {while (k--) if (m[k].time < r && k) m.splice(k, 1); m[0].time = n; p.save(bio_json, JSON.stringify(m, null, 3));} for (k = 0; k < m.length;k++) if (m[k].name == f) return true; return false;} catch (e) {return false;}}
    var update = function(f) {try {if (!p.file(bio_json)) return; var m = p.json_parse(utils.ReadTextFile(bio_json)), k = m.length, n = Date.now(); for (k = 0; k < m.length; k++) if (m[k].name == f) return; m.push({"name":f, "time":n}); p.save(bio_json, JSON.stringify(m, null, 3));} catch (e) {}}    
    var expired = function(f, exp, f_done, langCheck, type) {if (langCheck) switch (type) {case 0: for (var i = 0; i < similar.length; i++) if (langCheck.indexOf(similar[i]) != -1 && i != p.lfmLang_ix) return true; for (i = 0; i < listeners.length; i++) if (langCheck.indexOf(listeners[i]) != -1 && i != p.lfmLang_ix) return true; break; case 1: for (var i = 0; i < releaseDate.length; i++) if (langCheck.indexOf(releaseDate[i]) != -1 && i != p.lfmLang_ix) return true; for (i = 0; i < listeners.length; i++) if (langCheck.indexOf(listeners[i]) != -1 && i != p.lfmLang_ix) return true; break;} if (f_done && done(f_done, exp)) return false; if (!p.file(f)) return true; try {return Date.now() - Date.parse(p.fs.GetFile(f).DateLastModified) > exp;} catch (e) {return true;}}
    var cov_loc = function (n) {var yt_video = p.eval("%path%", n).replace(/[\.\/\\]/g, ""); yt_video = yt_video.indexOf("youtubecomwatch") != -1 ? true : false; return !p.ir() && !yt_video;}
    var check_match = function(n, l) {try {return 1 - levenshtein(n, l) / (n.length > l.length ? n.length : l.length) > 0.8;} catch (e) {return false}} // 0.8 sets fuzzy match level
    var levenshtein = function(a, b) {if (a.length === 0) return b.length; if (b.length === 0) return a.length; var i, j, prev, row, tmp, val; if (a.length > b.length) {tmp = a; a = b; b = tmp;} row = Array(a.length + 1); for (i = 0; i <= a.length; i++) row[i] = i; for (i = 1; i <= b.length; i++) {prev = i; for (j = 1; j <= a.length; j++) {if (b[i - 1] === a[j - 1]) val = row[j - 1]; else val = Math.min(row[j - 1] + 1, Math.min(prev + 1, row[j] + 1)); row[j - 1] = prev; prev = val;} row[a.length] = prev;} return row[a.length];}
    var compilation = function(n) {try {n = n.toLowerCase(); var kw = ["all the best", "all time greatest hits", "all-time greatest hits", "anthology", "at their best", "best of", "the best of", "very best of", "the very best of", "collection", "the collection", "definitive collection", "the definitive collection", "essential", "the essential", "essential collection", "the essential collection", "essentials", "the essentials", "gold", "gold greatest hits", "gold collection", "the gold collection", "greatest hits", "the greatest hits", "hits", "the hits", "platinum collection", "the platinum collection", "singles collection", "the singles collection", "super hits", "the ultimate collection", "ultimate collection"]; for (var i = 0; i < kw.length; i++) if (n == kw[i]) return true; return false;} catch (e) {}}
    var fallback = parseFloat(utils.ReadINI(p.bio_ini, "LASTFM LANGUAGE", p.lang[1].name)); if (fallback !== 1 && fallback !== 0) fallback = p.lang[1].tf;
    var lfm_server = p.lfmLang, def_server_EN = lfm_server == "www.last.fm", serverFallback = fallback && !def_server_EN;
    this.setLfm = function(lang) {if (lang) lfm_server = lang; lfm_server = lfm_server == "en" ? "www.last.fm" : "www.last.fm/" + lfm_server; def_server_EN = lfm_server == "www.last.fm"; serverFallback = fallback && !def_server_EN;}; this.setLfm();
    var listeners = ["Listeners", "Hörer", "Oyentes", "Auditeurs", "Ascoltatori", "リスナー", "Słuchaczy", "Ouvintes", "Слушатели", "Lyssnare", "Dinleyiciler", "听众"];
    var match = function(p_aa, p_l, list) {try {var aa = p.removeDiacritics(p_aa.replace(/^The /i, "").tidy()), l = p.removeDiacritics(p_l.tidy()), alb = [], art_m = []; for (var i = 0; i < list.length; i++) {alb[i] = p.removeDiacritics(list[i].nextSibling.innerText.tidy()); art_m[i] = p.removeDiacritics(list[i].nextSibling.nextSibling.innerText.replace(/^The /i, "").tidy()); if (l == alb[i] && art_m[i] == aa) return i;} if (!partial_match) return -1; for (i = 0; i < list.length; i++) if (alb[i].indexOf(l) != -1 && art_m[i].indexOf(aa) != -1) return i; for (i = 0; i < list.length; i++) if (check_match(l, alb[i]) && art_m[i].indexOf(aa) != -1) return i; return -1;} catch (e) {return -1;}}
    var noWiki = function(n) {try {return (/wiki|vikimiz|\u0412\u0438\u043A\u0438|\u7EF4\u57FA/i).test(n);} catch (e) {return false;}}
    var num_sort = function(data) {data.sort(function(a, b) {return a.m - b.m}); return data;}
    var obj_contains = function(arr, p_name) {var k = arr.length; while (k--) if (arr[k].p == p_name) return true; return false;}
    var partial_match = parseFloat(utils.ReadINI(p.bio_ini, "MISCELLANEOUS", p.def_tf[9].name)); if (partial_match !== 1 && partial_match !== 0) partial_match = p.def_tf[9].tf;
    var releaseDate = ["Release Date: ", "Veröffentlichungsdatum: ", "Fecha De Lanzamiento: ", "Date De Sortie: ", "Data Di Pubblicazione: ", "リリース日: ", "Data Wydania: ", "Data De Lançamento: ", "Дата релиза: ", "Utgivningsdatum: ", "Yayınlanma Tarihi: ", "发布日期: "]
    var res = function() {window.NotifyOthers("grab_txt_jb", "grab_txt_jb"); t.grab();}
    var similar = ["Similar Artists: ", "Ähnliche Künstler: ", "Artistas Similares: ", "Artistes Similaires: ", "Artisti Simili: ", "似ているアーティスト: ", "Podobni Wykonawcy: ", "Artistas Parecidos: ", "Похожие исполнители: ", "Liknande Artister: ", "Benzer Sanatçılar: ", "相似艺术家: "]
	var topAlb = ["Top Albums: ", "Top-Alben: ", "Álbumes Más Escuchados: ", "Top Albums: ", "Album Più Ascoltati: ", "人気アルバム: ", "Najpopularniejsze Albumy: ", "Álbuns Principais: ", "Популярные альбомы: ", "Toppalbum: ", "En Sevilen Albümler: ", "最佳专辑: "];
    this.fetch = function(force, n1, n2) {this.get_bio(force, n1, n2, force == 2 ? true : false); this.get_rev(force, n2, force == 2 ? true : false);}
    this.fetch_dynamic = function() {this.get_bio(false, [0, false], [0, false]);}
    function create_dl_file() {var n = fb.ProfilePath + "yttm\\foo_lastfm_img.vbs"; if (!p.file(n)) {var dl_im = "If (WScript.Arguments.Count <> 2) Then\r\nWScript.Quit\r\nEnd If\r\n\r\nurl = WScript.Arguments(0)\r\nfile = WScript.Arguments(1)\r\n\r\nSet objFSO = Createobject(\"Scripting.FileSystemObject\")\r\nIf objFSO.Fileexists(file) Then\r\nSet objFSO = Nothing\r\nWScript.Quit\r\nEnd If\r\n\r\nSet objXMLHTTP = CreateObject(\"MSXML2.XMLHTTP\")\r\nobjXMLHTTP.open \"GET\", url, false\r\nobjXMLHTTP.send()\r\n\r\nIf objXMLHTTP.Status = 200 Then\r\nSet objADOStream = CreateObject(\"ADODB.Stream\")\r\nobjADOStream.Open\r\nobjADOStream.Type = 1\r\nobjADOStream.Write objXMLHTTP.ResponseBody\r\nobjADOStream.Position = 0\r\nobjADOStream.SaveToFile file\r\nobjADOStream.Close\r\nSet objADOStream = Nothing\r\nEnd If\r\n\r\nSet objFSO = Nothing\r\nSet objXMLHTTP = Nothing"; p.save(n, dl_im);}}; if (p.server) create_dl_file();

    var img_exp = function(p_dl_ar, imgFolder, ex) {
        var allFiles = [], f = imgFolder + "update.txt", imgExisting = []; if (!p.file(f)) return [imgNo, 0, allFiles]; try {var last_upd = Date.parse(p.fs.GetFile(f).DateLastModified), getNew = Date.now() - last_upd > ex;} catch (e) {return [imgNo, 0, allFiles];} if (!getNew) return [0, auto_add, allFiles];
        allFiles = utils.Glob(imgFolder + "*").toArray(); var imNo = 0; for (var j = 0; j < allFiles.length; j++) if ((/_([a-z0-9]){32}\.jpg$/).test(p.fs.GetFileName(allFiles[j]))) {imNo++; if (artLimit) imgExisting.push({p:allFiles[j], m:Date.parse(p.fs.GetFile(allFiles[j]).DateLastModified)});} if (artLimit) num_sort(imgExisting); var newImgNo = imgNo - imNo;
        if (newImgNo > 0) return [newImgNo, 0, allFiles]; else if (!auto_add) {if (artLimit) {var remove = imgExisting.length - artLimit; if (remove > 0) {for (var j = 0; j < remove; j++) imgToDelete.push({a:p_dl_ar, p:imgExisting[j].p}); bioCacheSave(true);}} return [0, auto_add, allFiles];} else return [5, auto_add, allFiles, imgExisting];
    }

    this.get_bio = function(force, n1, n2, onlyForceLfm) {
        var artist_done = false, fn_bio, pth_bio, stndBio = !n1[0] || n1[0] + 1 > n1[2].length , new_artist = stndBio ? name.artist(n1[1]) : n1[2][n1[0]].name, supCache = false;
        if (new_artist == artist && !force || new_artist == "") artist_done = true; else artist = new_artist;
        if (!stndBio) supCache = p.supCache && !lib.in_library(0, artist);
        if (this.lfm_bio && !artist_done) {
            pth_bio = stndBio ? p.cleanPth(p.lfmBioPth, n1[1]) : p.cleanMul(p.lfmBioMul, artist, "", n1[1], 1); fn_bio = pth_bio + artist.clean() + ".txt"; if (supCache && !p.file(fn_bio)) {pth_bio = p.cleanMul(p.lfmBioSup, artist, "", n1[1], 1); fn_bio = pth_bio + artist.clean() + ".txt";}
            var text = utils.ReadTextFile(fn_bio), custBio = text.indexOf("Custom Biography") != -1;
            if (expired(fn_bio, exp, "", text, 0) && !custBio || force == 2 && !custBio || force == 1) {var dl_lfm_bio = new dl_lastfm_bio(function() {dl_lfm_bio.on_state_change();}); dl_lfm_bio.Search(artist, pth_bio, fn_bio, force);}
        }
        if (!artist_done) {
            if (this.dl_art_img) dl_art.run(artist, force, n1, stndBio, supCache); else timer.decelerating(p.rev_img || serv.lfm_cov && cov_loc() ? true : false);
            if (p.lfm_sim && stndBio) {
                var len = 0, pth_sim = p.cleanPth(p.lfmSimPth), fn_sim = pth_sim + artist.clean() + " And Similar Artists.json", valid = false;
                if (p.file(fn_sim)) {var list = p.json_parse(utils.ReadTextFile(fn_sim)); if (list) {valid = list[0].hasOwnProperty('name'); len = list.length;}}
                if (expired(fn_sim, exp) || !valid || force) {var dl_lfm_sim = new lfm_similar_artists(function() {dl_lfm_sim.on_state_change();}); dl_lfm_sim.Search(artist, "", "", len > 101 ? 249 : 100, pth_sim, fn_sim);}
            }
            if (stndBio && artLimit) {
                var j = imgToDelete.length; while (j--) {
                    if (imgToDelete[j].a != name.artist(true) && imgToDelete[j].a != name.artist(false)) {
                    try {if (p.file(imgToDelete[j].p)) p.fs.DeleteFile(imgToDelete[j].p);} catch (e) {}
                    if (!p.file(imgToDelete[j].p)) imgToDelete.splice(j, 1)
                    }
                }
                bioCacheSave(true);
            }
        }
        if (!stndBio && !force || onlyForceLfm) return;
        if (this.am_bio && !this.am_rev) {
            var stndAlb = !n2[0] || n2[0] + 1 > n2[2].length, new_alb_id = stndAlb ? p.eval("%album artist%%album%", n2[1]) : n2[2][n2[0]].artist + n2[2][n2[0]].album;
            if (new_alb_id == alb_id && !force) return;
            alb_id = new_alb_id; album = stndAlb ? name.album(n2[1]) : n2[2][n2[0]].album; alb_artist = stndBio ? name.alb_artist(n1[1]) : artist; if (!album || !alb_artist) return;
            var fn_rev = (stndBio ? p.cleanPth(p.amRevPth, n1[1]) : p.cleanMul(p.amRevMul, artist, album, n1[1], 0)) + alb_artist.clean() + " - " + album.clean() + ".txt";
            pth_bio = stndBio ? p.cleanPth(p.amBioPth, n1[1]) : p.cleanMul(p.amBioMul, artist, "", n1[1], 1); fn_bio = pth_bio + artist.clean() + ".txt";
            if (supCache && !p.file(fn_bio)) {pth_bio = p.cleanMul(p.amBioSup, artist, "", n1[1], 1); fn_bio = pth_bio + artist.clean() + ".txt"; fn_rev = p.cleanMul(p.amRevSup, artist, album, n1[1], 0) + alb_artist.clean() + " - " + album.clean() + ".txt";}
            if (force || expired(fn_bio, exp, "Bio " + partial_match + " " + fn_rev, false) && utils.ReadTextFile(fn_bio).indexOf("Custom Biography") == -1) {var dl_am_bio = new dl_allmusic_bio(function() {dl_am_bio.on_state_change();}); dl_am_bio.Search(0, "https://www.allmusic.com/search/albums/" + encodeURIComponent(!compilation(album) ? album : alb_artist + " " + album.replace(/^The /i, "")), album, alb_artist, artist, "bio", "", fn_rev, pth_bio, fn_bio, force);}
        }
    }

    this.get_rev = function(force, n, onlyForceLfm) {
        var stndAlb = !n[0] || n[0] + 1 > n[2].length, new_album_id = stndAlb ? p.eval("%album artist%%album%", n[1]) : n[2][n[0]].artist + n[2][n[0]].album, supCache = false;
        if (new_album_id == album_id && !force) return;
        album_id = new_album_id; album = stndAlb ? name.album(n[1]) : n[2][n[0]].album; albm = stndAlb ? name.albm(n[1]) : n[2][n[0]].album; alb_artist = stndAlb ? name.alb_artist(n[1]) : n[2][n[0]].artist;
        if (!album || !alb_artist) return;
        if (!stndAlb) supCache = p.supCache && !lib.in_library(1, alb_artist, album);
        var pth_rev = "", fn_rev = "";
        if (stndAlb) {if (albm) this.get_cover(force, n);} else if (force) this.get_rev_img(alb_artist, album, "", "", force);
        if (this.am_rev && !onlyForceLfm) {
            pth_rev = stndAlb ? p.cleanPth(p.amRevPth, n[1]) : p.cleanMul(p.amRevMul, alb_artist, album, n[1], 0); fn_rev = pth_rev + alb_artist.clean() + " - " + album.clean() + ".txt";
            if (supCache && !p.file(fn_rev)) {pth_rev = p.cleanMul(p.amRevSup, alb_artist, album, n[1], 0); fn_rev = pth_rev + alb_artist.clean() + " - " + album.clean() + ".txt";}
            var artiste = stndAlb ? name.artist(n[1]) : alb_artist; pth_bio = stndAlb ? p.cleanPth(p.amBioPth, n[1]) : p.cleanMul(p.amBioMul, artiste, "", n[1], 1); fn_bio = pth_bio + artiste.clean() + ".txt";
            if (!stndAlb && p.supCache && !p.file(fn_bio) && !lib.in_library(0, artiste)) {pth_bio = p.cleanMul(p.amBioSup, artiste, "", n[1], 1); fn_bio = pth_bio + artiste.clean() + ".txt";}
            var art_upd = expired(fn_bio, exp, "Bio " + partial_match + " " + fn_rev, false) && utils.ReadTextFile(fn_bio).indexOf("Custom Biography") == -1, dn_type = "";
			var rev_upd = !done("Rev " + partial_match + " " + fn_rev, exp);
			if (rev_upd) {
				var amRev = utils.ReadTextFile(fn_rev);
				rev_upd = !amRev || (amRev.indexOf("Genre: ") == -1 || amRev.indexOf("Review by ") == -1 && p.last_modified(fn_rev) < exp) && amRev.indexOf("Custom Review") == -1;
			}
            if (rev_upd || art_upd || force) {
                if ((this.am_rev && rev_upd) && (this.am_bio && art_upd) || force) dn_type = "both"; else if (this.am_rev && rev_upd || force) dn_type = "review"; else if (this.am_bio && art_upd || force) dn_type = "bio";
                var dl_am_bio = new dl_allmusic_bio(function() {dl_am_bio.on_state_change();}); dl_am_bio.Search(0, "https://www.allmusic.com/search/albums/" + encodeURIComponent(!compilation(album) ? album : alb_artist + " " + album.replace(/^The /i, "")), album, alb_artist, artiste, dn_type, pth_rev, fn_rev, pth_bio, fn_bio, force);
            }
        }
        if (!this.lfm_rev) return;
        pth_rev = stndAlb ? p.cleanPth(p.lfmRevPth, n[1]) : p.cleanMul(p.lfmRevMul, alb_artist, album, n[1], 0); fn_rev = pth_rev + alb_artist.clean() + " - " + album.clean() + ".txt";
        if (supCache && !p.file(fn_rev)) {pth_rev = p.cleanMul(p.lfmRevSup, alb_artist, album, n[1], 0); fn_rev = pth_rev + alb_artist.clean() + " - " + album.clean() + ".txt";}
        var text = utils.ReadTextFile(fn_rev), custRev = text.indexOf("Custom Review") != -1;
        if ((!expired(fn_rev, exp, "", text, 1) || custRev) && !force || custRev && force == 2) return;
        var lfm_alb = new lastfm_alb(function() {lfm_alb.on_state_change();}); lfm_alb.Search(alb_artist, album, true, pth_rev, fn_rev, "", force, false);
    }

    this.get_cover = function(force, n) {if (!cov_loc(n[1])) return; // stndAlb
        switch (this.lfm_cov) {
            case 1: // cover
                var handle = p.handle(n[1]); if (!handle) return; var g_img = utils.GetAlbumArtV2(handle, 0, false); if (g_img) return g_img.Dispose();
                var pth_cov = p.cleanPth(p.imgCovPth, n[1]), fn_cov = pth_cov + p.eval(p.imgCovFn, n[1]).clean();
                if (done(alb_artist + " - " + album + " " +  auto_corr + " " + fn_cov, exp) && !force) return;
                for (var k = 0; k < ext.length; k++) if (p.file(fn_cov + ext[k])) return;
                if (p.extra) for (var j = 0; j < p.extraPaths.length; j++) for (k = 0; k < ext.length; k++) if (p.file(p.eval(p.extraPaths[j] + ext[k], n[1]))) return;
                var lfm_cov = new lastfm_alb(function() {lfm_cov.on_state_change();}); lfm_cov.Search(alb_artist, album, false, pth_cov, fn_cov, albm, force, false);
                break;
            case 0: // rev_img
                var handle = p.handle(n[1]); if (!handle) return; var g_img = utils.GetAlbumArtV2(handle, 0, false); if (g_img) return g_img.Dispose();
                var pth_cov = p.cleanMul(p.imgRevMul, alb_artist, album, n[1], 0), 
                fn_cov = [pth_cov + alb_artist.clean() + " - " + album.clean(), p.cleanPth(p.imgCovPth, n[1]) + p.eval(p.imgCovFn, n[1]).clean()];
                if (done(alb_artist + " - " + album + " " +  auto_corr + " " + fn_cov[0], exp) && !force) return;
                for (var j = 0; j < fn_cov.length; j++) for (var k = 0; k < ext.length; k++) {var ep = fn_cov[j] + ext[k]; if (p.file(ep)) return;}
                if (p.extra) for (j = 0; j < p.extraPaths.length; j++) for (k = 0; k < ext.length; k++) if (p.file(p.eval(p.extraPaths[j] + ext[k], n[1]))) return;
                var lfm_cov = new lastfm_alb(function() {lfm_cov.on_state_change();}); lfm_cov.Search(alb_artist, album, false, pth_cov, fn_cov[0], albm, force, true);
                break;
            }
    }

    this.get_rev_img = function(a, l, pe, fe, force) { // !stndAlb
        if (!force) {if (done(a + " - " + l + " " +  auto_corr + " " + fe, exp)) return; var lfm_cov = new lastfm_alb(function() {lfm_cov.on_state_change();}); lfm_cov.Search(a, l, false, pe, fe, l, false, true);}
        else {
            var metadb = lib.in_library(2, a, l);
            if (metadb) {var g_img = utils.GetAlbumArtV2(metadb, 0, false); if (g_img) return g_img.Dispose();}
            else {
                var pe = [p.cleanMul(p.imgRevMul, a, l, "", 0)], fe = a.clean() + " - " + l.clean(); if (p.supCache) pe.push(p.cleanMul(p.imgRevSup, a, l, "", 0));
                for (var j = 0; j < pe.length; j++) for (var k = 0; k < ext.length; k++) if (p.file(pe[j] + fe + ext[k])) return;
                var lfm_cov = new lastfm_alb(function() {lfm_cov.on_state_change();}); lfm_cov.Search(a, l, false, pe[p.supCache], pe[p.supCache] + fe, l, true, true);
            }
        }
    }

    function dl_allmusic_bio(state_callback) {
        var alb_artist, album, artist = "", artistLink = "", dn_type = "", fn_bio, fn_rev, pth_bio, pth_rev, sw = 0; this.xmlhttp = null; this.func = null; this.ready_callback = state_callback; this.ie_timer = false;
        this.on_state_change = function() {if (this.xmlhttp != null && this.func != null) if (this.xmlhttp.readyState == 4) {window.ClearTimeout(this.ie_timer); this.ie_timer = false; if (this.xmlhttp.status == 200) this.func(); else {p.trace("allmusic album review / biography: " + album + " / " + alb_artist + ": not found" + " Status error: " + this.xmlhttp.status, true);}}}

        this.Search = function(p_sw, URL, p_album, p_alb_artist, p_artist, p_dn_type, p_pth_rev, p_fn_rev, p_pth_bio, p_fn_bio, force) {
            sw = p_sw; if (!sw) {dn_type = p_dn_type; pth_rev = p_pth_rev; fn_rev = p_fn_rev; pth_bio = p_pth_bio; fn_bio = p_fn_bio; album = p_album; alb_artist = p_alb_artist; artist = p_artist;}
            this.func = null; this.xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
            this.func = this.Analyse; this.xmlhttp.open("GET", URL); this.xmlhttp.onreadystatechange = this.ready_callback; if (force) this.xmlhttp.setRequestHeader('If-Modified-Since', 'Thu, 01 Jan 1970 00:00:00 GMT'); this.xmlhttp.send();
            if (!this.ie_timer) {var a = this.xmlhttp, that = this; this.ie_timer = window.SetTimeout(function() {a.abort(); that.ie_timer = false;}, 30000);}
        }
        
        this.Analyse = function() {
            var doc = new ActiveXObject("htmlfile"), i = 0; doc.open(); var div = doc.createElement("div");
                switch (sw) {
                    case 0:
                        try {div.innerHTML = this.xmlhttp.responsetext;
                        var list = div.getElementsByTagName("h4"), links = [], va = alb_artist.toLowerCase() == p.va || alb_artist.toLowerCase() != artist.toLowerCase(); i = match(alb_artist, album, list);
                        if (i != -1) {
                            if (!va) artistLink = list[i].nextSibling.nextSibling.firstChild.getAttribute("href");
                            if (dn_type == "both" || dn_type == "review") {sw = 1; doc.close(); return this.Search(sw, list[i].nextSibling.firstChild.getAttribute("href"));}
                            else if (dn_type == "bio" && !va) {sw = 2; doc.close(); return this.Search(sw, artistLink + "/biography");}
                        } update("Bio " + partial_match + " " + fn_rev); update("Rev " + partial_match + " " + fn_rev); p.trace("allmusic album review / biography: " + album + " / " + alb_artist + ": not found", true);
                        } catch (e) {update("Bio " + partial_match + " " + fn_rev); update("Rev " + partial_match + " " + fn_rev); p.trace("allmusic album review / biography: " + album + " / " + alb_artist + ": not found", true);}
						doc.close();
                        break;
                    case 1:
                        try {div.innerHTML = this.xmlhttp.responsetext;
                        var a = div.getElementsByTagName("a"), li = div.getElementsByTagName("li"), dv = div.getElementsByTagName("div"), str = "";
                        var rating = "x", releaseDate = "", review = "", reviewAuthor = "", reviewGenre = [], reviewMood = [], reviewTheme = [];
						ui.htmlParse(dv, 'className', 'text', function(v) {review = v.innerHTML.format()});
                        for (i = 0; i < dv.length; i++) if (dv[i].className == "release-date") releaseDate = (dv[i](0).childNodes(0).innerText + ": " + dv[i](0).childNodes(1).innerText).trim();
                        for (i = 0; i < a.length; i++) {str = a[i](0).toString(); if (str.indexOf("www.allmusic.com/genre") != -1 || str.indexOf("www.allmusic.com/style") != -1) {var tg = a[i](0).innerText.trim(); if (tg) reviewGenre.push(tg);}}
                        for (i = 0; i < a.length; i++) {str = a[i](0).toString(); if (str.indexOf("www.allmusic.com/mood") != -1) {var tm = a[i](0).innerText.trim(); if (tm) reviewMood.push(tm);} if (str.indexOf("www.allmusic.com/theme") != -1) {var tth = a[i](0).innerText.trim(); if (tth) reviewTheme.push(tth);}}
                        if (releaseDate.length) releaseDate = "\r\n\r\n" + releaseDate;
                        if (reviewGenre.length) reviewGenre = "\r\n\r\n" + "Genre: " + reviewGenre.join(", ");
                        if (reviewMood.length) reviewMood = "\r\n\r\n" + "Album Moods: " + reviewMood.join(", ");
                        if (reviewTheme.length) reviewTheme = "\r\n\r\n" + "Album Themes: " + reviewTheme.join(", ");
                        ui.htmlParse(div.getElementsByTagName('h3'), 'className', 'review-author headline', function(v) {reviewAuthor = v.innerHTML.format()}); if (reviewAuthor) reviewAuthor = "\r\n\r\n" + reviewAuthor;
                        review = review + reviewGenre + reviewMood + reviewTheme + releaseDate + reviewAuthor;
						review = review.trim();
                        for (i = 0; i < li.length; i++) if (li[i].id == "microdata-rating") rating = li[i](0).childNodes(2).innerText / 2;
                        review = ">> Album rating: " + rating + " <<  " + review;
                        if (review.length > 22) {p.buildFullPth(pth_rev); p.save(fn_rev, review); res();} else {update("Rev " + partial_match + " " + fn_rev); p.trace("allmusic album review: " + album + " / " + alb_artist + ": not found", true);}
                        } catch (e) {update("Rev " + partial_match + " " + fn_rev); p.trace("allmusic album review: " + album + " / " + alb_artist + ": not found", true);}
						doc.close();
                        if (dn_type != "both") return;
                        if (artistLink) {sw = 2; return this.Search(sw, artistLink + "/biography");} p.trace("allmusic biography: " + artist + ": not found", true);
                        break;
                    case 2:
                        try {div.innerHTML = this.xmlhttp.responsetext;
                        var a = div.getElementsByTagName("a"), dv = div.getElementsByTagName("div"), str = "";
                        var active = "", biography = "", biographyAuthor = "", biographyGenre = [];
						ui.htmlParse(dv, 'className', 'text', function(v) {biography = v.innerHTML.format()});
                        for (i = 0; i < dv.length; i++) if (dv[i].className == "active-dates") active = (dv[i](0).childNodes(0).innerText + ": " + dv[i](0).childNodes(1).innerText).trim();
                        for (i = 0; i < a.length; i++) {str = a[i](0).toString(); if (str.indexOf("www.allmusic.com/genre") != -1 || str.indexOf("www.allmusic.com/style") != -1) {var tg = a[i](0).innerText.trim(); if (tg) biographyGenre.push(tg);}}
                        if (active.length) active = "\r\n\r\n" + active;
                        if (biographyGenre.length) biographyGenre = "\r\n\r\n" + "Genre: " + biographyGenre.join(", ");
                        ui.htmlParse(div.getElementsByTagName('h3'), 'className', 'headline', function(v) {biographyAuthor = v.innerHTML.format()}); if (biographyAuthor) biographyAuthor = "\r\n\r\n" + biographyAuthor;
                        biography = biography + biographyGenre + active + biographyAuthor;
						biography = biography.trim();
                        if (biography.length > 19) {p.buildFullPth(pth_bio); p.save(fn_bio, biography); res();} else {update("Bio " + partial_match + " " + fn_rev); p.trace("allmusic biography: " + artist + ": not found", true);}
                        } catch (e) {update("Bio " + partial_match + " " + fn_rev); p.trace("allmusic biography: " + artist + ": not found", true);}
						doc.close();
                        break;
                }
        }
    }

    function dl_lastfm_bio(state_callback) {
        var artist, con = "", counts = ["", ""], fn_bio, popAlbums = [], pth_bio, retry = false, scrobbles = ["", ""], searchBio = 0, simArtists = [], tags = [], topAlbums = []; this.xmlhttp = null; this.func = null; this.ready_callback = state_callback; this.ie_timer = false;
        this.on_state_change = function() {if (this.xmlhttp != null && this.func != null) if (this.xmlhttp.readyState == 4) {window.ClearTimeout(this.ie_timer); this.ie_timer = false; if (this.xmlhttp.status == 200) this.func(); else {if (searchBio < 2) {searchBio++; this.Search(artist, pth_bio, fn_bio);} if (searchBio == 2) this.func(true);}}}

        this.Search = function(p_artist, p_pth_bio, p_fn_bio, force) {
            artist = p_artist; pth_bio = p_pth_bio; fn_bio = p_fn_bio;
            this.func = null; this.xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
            var URL = searchBio == 2 ? "https://www.last.fm/music/" + encodeURIComponent(artist) + "/+albums" : "https://" + (!retry ? lfm_server : "www.last.fm") + "/music/" + encodeURIComponent(artist) + (searchBio ? "/+wiki" : "");
            this.func = this.Analyse; this.xmlhttp.open("GET", URL); this.xmlhttp.onreadystatechange = this.ready_callback; if (force) this.xmlhttp.setRequestHeader('If-Modified-Since', 'Thu, 01 Jan 1970 00:00:00 GMT'); this.xmlhttp.send();
            if (!this.ie_timer) {var a = this.xmlhttp, that = this; this.ie_timer = window.SetTimeout(function() {a.abort(); that.ie_timer = false;}, 30000);}
        }
        
        this.Analyse = function(saveOnly) {
			if (!saveOnly) {
				var doc = new ActiveXObject("htmlfile"), i = 0; doc.open(); var div = doc.createElement("div"); div.innerHTML = this.xmlhttp.responsetext;
				switch (searchBio) {
					case 0:
						var h3 = div.getElementsByTagName('h3'), h4 = div.getElementsByTagName("h4"), j = 0;
						ui.htmlParse(div.getElementsByTagName('li'), 'className', 'tag', function(v) {tags.push(v.innerText.trim().titlecase().replace(/\bAor\b/g, "AOR").replace(/\bDj\b/g, "DJ").replace(/\bFc\b/g, "FC").replace(/\bIdm\b/g, "IDM").replace(/\bNwobhm\b/g, "NWOBHM").replace(/\bR&b\b/g, "R&B").replace(/\bRnb\b/g, "RnB").replace(/\bUsa\b/g, "USA").replace(/\bUs\b/g, "US").replace(/\bUk\b/g, "UK"))});
						ui.htmlParse(h3, 'className', 'catalogue-overview-similar-artists-full-width-item-name', function(v) {simArtists.push(v.innerText.trim().titlecase())});
						ui.htmlParse(h4, 'className', 'header-metadata-tnew-title', function(v) {scrobbles[j] = v.innerText.trim().titlecase(); j++;}); j = 0;
						ui.htmlParse(div.getElementsByTagName('abbr'), 'className', 'intabbr js-abbreviated-counter', function(v) {counts[j] = v.innerText.trim().titlecase(); j++;});
						if (tags.length) tags = "\r\n\r\n" + "Top Tags: " + tags.join(", "); else tags = "";
						if (simArtists.length) {simArtists.length = Math.min(4, simArtists.length); simArtists = "\r\n\r\n" + similar[p.lfmLang_ix] + simArtists.join(", ");} else simArtists = ""; doc.close();
						searchBio = 1; return this.Search(artist, pth_bio, fn_bio)
					case 1:
						var factbox = "", li = div.getElementsByTagName("li"), lis = div.getElementsByTagName("div"), links = []; con = "";
						for (i = 0; i < lis.length; i++) if (lis[i].className == "wiki-content") {con = lis[i].innerHTML.format(); break;}
						for (i = 0; i < li.length; i++) {if (li[i].className == "factbox-item") {factbox = ""; factbox = li[i].innerHTML.replace(/<\/H4>/gi, ": ").replace(/\s*<\/LI>\s*/gi, ", ").replace(/\s*Show all members…\s*/gi, "").format().replace(/,$/, ""); if (factbox) con += ("\r\n\r\n" + factbox);}}
						doc.close();
						if (!retry) {searchBio = 2; return this.Search(artist, pth_bio, fn_bio);}
						break;
					case 2:
						i = 0;
						ui.htmlParse(div.getElementsByTagName('h3'), 'className', 'resource-list--release-list-item-name', function(v) {i < 4 ? popAlbums.push(v.innerText.trim().titlecase()) : topAlbums.push(v.innerText.trim().titlecase()); i++; if (i == 10) return true;});
						doc.close();
						if (popAlbums.length) {
							var mapAlbums = [];
							for (i = 0; i < topAlbums.length; i++) mapAlbums.push(topAlbums[i].cut()); var match = false;
							for (i = 0; i < mapAlbums.length; i++) if (mapAlbums[i].indexOf(popAlbums[0].cut()) == 0) {match = true; break;}
							if (topAlbums.length > 5 && !match) topAlbums.splice(5, 0, popAlbums[0]); else topAlbums = topAlbums.concat(popAlbums);
						}
						topAlbums.length = Math.min(6, topAlbums.length);
						if (topAlbums.length) topAlbums = "\r\n\r\n" + topAlb[p.lfmLang_ix] + topAlbums.join(", "); else topAlbums = "";
						break;
				}
			}
            if ((!con.length || con.length < 45 && noWiki(con)) && serverFallback && !retry) {retry = true; searchBio = 1; return this.Search(artist, pth_bio, fn_bio);}
            if (con.length < 45 && noWiki(con)) con = "";
            con += tags; con += topAlbums; con += simArtists; if (scrobbles[0].length && counts[0].length || scrobbles[1].length && counts[1].length) con += ("\r\n\r\nLast.fm: " + (counts[0].length ? scrobbles[0] + " " + counts[0] + "; " : "") + (counts[1].length ? scrobbles[1] + " " + counts[1] : "")); con = con.trim();
            if (!con.length) {update(lfm_server + (serverFallback ? " www.last.fm" : "") + " " + fn_bio); p.trace("last.fm biography: " + artist +  ": not found", true); return;}
            p.buildFullPth(pth_bio); p.save(fn_bio, con); res(); p.get_multi(false); window.NotifyOthers("get_multi_jb", "get_multi_jb");
        }
    }

    function dl_art_images() {
        this.run = function(dl_ar, force, n, p_stndBio, p_supCache) {
            if (!p.file(fb.ProfilePath + "yttm\\foo_lastfm_img.vbs")) return; var img_folder = "";
            var img_folder = p_stndBio ? p.cleanPth(p.imgArtPth, n[1]) : p.cleanMul(p.imgArtMul, dl_ar, "", n[1], 1); if (p_supCache && !p.folder(img_folder)) img_folder = p.cleanMul(p.imgArtSup, dl_ar, "", n[1], 1);
            var getNo = img_exp(dl_ar, img_folder, !force ? exp : 0); if (!getNo[0]) return; var lfm_art = new lfm_art_img(function() {lfm_art.on_state_change();}); lfm_art.Search(dl_ar, img_folder, getNo[0], getNo[1], getNo[2], getNo[3], force);
        }
    }
    if (this.dl_art_img) var dl_art = new dl_art_images();

    function lfm_art_img(state_callback) {
        var allFiles, autoAdd, dl_ar, getNo, imgExisting, img_folder, retry = false; this.xmlhttp = null; this.func = null; this.ready_callback = state_callback; this.ie_timer = false;
        this.on_state_change = function() {if (this.xmlhttp != null && this.func != null) if (this.xmlhttp.readyState == 4) {window.ClearTimeout(this.ie_timer); this.ie_timer = false; if (this.xmlhttp.status == 200) this.func(); else {p.trace("last.fm artist images: " + dl_ar + ": none found" + " Status error: " + this.xmlhttp.status, true);}}}

        this.Search = function(p_dl_ar, p_img_folder, p_getNo, p_autoAdd, p_allFiles, p_imgExisting, force) {
            dl_ar = p_dl_ar; img_folder = p_img_folder; getNo = p_getNo; autoAdd = p_autoAdd; allFiles = p_allFiles; imgExisting = p_imgExisting;
            this.func = null; this.xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
            var URL = "https://" + (!retry ? lfm_server : "www.last.fm") +"/music/" + encodeURIComponent(dl_ar) + "/+images";
            this.func = this.Analyse; this.xmlhttp.open("GET", URL); this.xmlhttp.onreadystatechange = this.ready_callback; if (force) this.xmlhttp.setRequestHeader('If-Modified-Since', 'Thu, 01 Jan 1970 00:00:00 GMT'); this.xmlhttp.send();
            if (!this.ie_timer) {var a = this.xmlhttp, that = this; this.ie_timer = window.SetTimeout(function() {a.abort(); that.ie_timer = false;}, 30000);}
        }

        this.Analyse = function() {
            var a = dl_ar.clean(), doc = new ActiveXObject("htmlfile"); doc.open();
            var div = doc.createElement("div"); div.innerHTML = this.xmlhttp.responsetext;
            var list = div.getElementsByTagName("img"), links = []; if (!list) {if (serverFallback && !retry) {retry = true; doc.close(); return this.Search(dl_ar, img_folder);} doc.close(); return p.trace("last.fm artist images: " + dl_ar + ": none found", true);} 
			ui.htmlParse(list, false, false, function(v) {var attr = v.getAttribute("src"); if (attr.includes("avatar170s/")) links.push(attr.replace("avatar170s/", ""));});
			doc.close();
            if (links.length) {
                p.buildFullPth(img_folder); if (p.folder(img_folder)) {
                    if (autoAdd && artLimit) {
                        var noNewLinks = 0; for (var k = 0; k < Math.min(links.length, 5); k++) {var iPth = img_folder + a + "_" + links[k].substring(links[k].lastIndexOf("/") + 1) + ".jpg"; if (!obj_contains(imgExisting, iPth)) noNewLinks++; if (noNewLinks == 5) break;}
                        var remove = imgExisting.length + noNewLinks - artLimit; remove = Math.min(remove, imgExisting.length); if (remove > 0) {for (k = 0; k < remove; k++) imgToDelete.push({a:a, p:imgExisting[k].p}); bioCacheSave(true);}
                    }
                    p.save(img_folder + "update.txt", ""); timer.decelerating(cov_loc() ? true : false); 
                    if (autoAdd) for (var j = 0; j < Math.min(links.length, getNo); j++) ui.run("cscript //nologo \"" + fb.ProfilePath + "yttm\\foo_lastfm_img.vbs\" \"" + links[j] + "\" \"" + img_folder + a + "_" + links[j].substring(links[j].lastIndexOf("/") + 1) + ".jpg" + "\"", 0);
                    else {var c = 0; for (var j = 0; j < Math.min(links.length, imgNo); j++) {var imPth = img_folder + a + "_" + links[j].substring(links[j].lastIndexOf("/") + 1) + ".jpg"; if (!img.arr_contains(allFiles, imPth)) {ui.run("cscript //nologo \"" + fb.ProfilePath + "yttm\\foo_lastfm_img.vbs\" \"" + links[j] + "\" \"" + imPth + "\"", 0); c++; if (c == getNo) break;}}}
                }
            }
        }
    }

    function lastfm_alb(state_callback) {
        var alb_artist, albm, album, con = "", counts = ["", "", ""], doc = new ActiveXObject("htmlfile"), fn, getStats = true, path, rd = "", rd_n = "", retry = false, rev, rev_img, scrobbles = ["", "", ""], stats = "", tags = [], tr = "", URL = ""; this.xmlhttp = null; this.func = null; this.ready_callback = state_callback; this.ie_timer = false;
        this.on_state_change = function() {if (this.xmlhttp != null && this.func != null) if (this.xmlhttp.readyState == 4) {window.ClearTimeout(this.ie_timer); this.ie_timer = false; if (this.xmlhttp.status == 200) this.func(); else {p.trace("last.fm album " + (rev ? "review: " :"cover: ") + album + " / " + alb_artist + ": not found" + " Status error: " + this.xmlhttp.status, true);}}}

        this.Search = function(p_alb_artist, p_album, p_rev, p_path, p_fn, p_albm, force, p_rev_img) {
            alb_artist = p_alb_artist; album = p_album; rev = p_rev; path = p_path; fn = p_fn; albm = p_albm; rev_img = p_rev_img;
            if (!getStats && rev || !rev) {
                URL = "http://ws.audioscrobbler.com/2.0/?format=json" + p.lfm; if (rev && !def_server_EN && !retry) URL += "&lang=" + p.lfmLang;
                URL += "&method=album.getInfo&artist=" + encodeURIComponent(alb_artist) + "&album=" + encodeURIComponent(rev || retry ? album : albm) + "&autocorrect=" + auto_corr;
        } else URL = "https://" + lfm_server + "/music/" + encodeURIComponent(alb_artist) + "/" + encodeURIComponent(album);
            this.func = null; this.xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
            this.func = this.Analyse; this.xmlhttp.open("GET", URL); this.xmlhttp.onreadystatechange = this.ready_callback;
            this.xmlhttp.setRequestHeader('User-Agent', "foobar2000_script"); if (force) this.xmlhttp.setRequestHeader('If-Modified-Since', 'Thu, 01 Jan 1970 00:00:00 GMT'); this.xmlhttp.send();
            if (!this.ie_timer) {var a = this.xmlhttp, that = this; this.ie_timer = window.SetTimeout(function() {a.abort(); that.ie_timer = false;}, 30000);}
        }

        this.Analyse = function() {
            if (!getStats && rev) {
                var wiki = p.json_parse(this.xmlhttp.responsetext, "album.wiki.content", "name\":");
                if (!wiki) {if (serverFallback && !retry) {retry = true; return this.Search(alb_artist, album, rev, path, fn);} if (!stats.length) return p.trace("last.fm album review: " + album + " / " + alb_artist + ": not found", true);}
                else {wiki = wiki.replace(/<[^>]+>/ig,""); var f = wiki.indexOf(" Read more on Last.fm"); if (f != -1) wiki = wiki.slice(0, f); wiki = wiki.replace(/\n/g, "\r\n").replace(/(\r\n)(\r\n)+/g, "\r\n\r\n").trim();}
                wiki = wiki ? wiki + tags + stats : tags + stats; wiki = wiki.trim(); p.buildFullPth(path); p.save(fn, wiki); res();
            } else if (rev) {
                doc.open(); var div = doc.createElement("div"); div.innerHTML = this.xmlhttp.responsetext; var j = 0;
                ui.htmlParse(div.getElementsByTagName('li'), 'className', 'tag', function(v) {tags.push(v.innerText.trim().titlecase().replace(/\bAor\b/g, "AOR").replace(/\bDj\b/g, "DJ").replace(/\bFc\b/g, "FC").replace(/\bIdm\b/g, "IDM").replace(/\bNwobhm\b/g, "NWOBHM").replace(/\bR&b\b/g, "R&B").replace(/\bRnb\b/g, "RnB").replace(/\bUsa\b/g, "USA").replace(/\bUs\b/g, "US").replace(/\bUk\b/g, "UK"))});
				ui.htmlParse(div.getElementsByTagName('dt'), 'className', 'catalogue-metadata-heading', function(v) {if (j) {rd_n = v.innerText.trim().titlecase(); return true;} j++;}); j = 0;
				ui.htmlParse(div.getElementsByTagName('dd'), 'className', 'catalogue-metadata-description', function(v) {if (!j) tr = v.innerText.trim().replace(/\b1 tracks/, "1 track").split(',')[0]; else {rd = v.innerText.trim(); return true;} j++;}); j = 0;
				ui.htmlParse(div.getElementsByTagName('h4'), 'className', 'header-metadata-tnew-title', function(v) {scrobbles[j] = v.innerText.trim().titlecase(); j++}); j = 0;
				ui.htmlParse(div.getElementsByTagName('abbr'), 'className', 'intabbr js-abbreviated-counter', function(v) {counts[j] = v.innerText.trim().titlecase(); j++});
                doc.close();
                if (tags.length) {tags.length = 5; tags = "\r\n\r\n" + "Top Tags: " + tags.join(", ");} else tags = "";
                if (rd_n && rd && (/\d\d\d\d/).test(rd)) stats += ("\r\n\r\n" + rd_n + ": " + rd + (tr ? " | " + tr : ""));
				if (scrobbles[1].length && counts[1].length || scrobbles[0].length && counts[0].length) stats += ("\r\n\r\nLast.fm: " + (counts[1].length ? scrobbles[1] + " " + counts[1] + "; " : "") + (counts[1].length ? scrobbles[0] + " " + counts[0] : ""));
				if (scrobbles[2] && counts[2] && scrobbles[2] != scrobbles[0] && scrobbles[1] != scrobbles[0]) stats += ("\r\n\r\n" + "Rating: " + scrobbles[2] + ": " + counts[2]);
                getStats = false; return this.Search(alb_artist, album, rev, path, fn);
            } else {
                if (!p.file(fb.ProfilePath + "yttm\\foo_lastfm_img.vbs")) return;
                var data = p.json_parse(this.xmlhttp.responsetext, "album.image", "name\":"); if (!data || data.length < 5) {update(alb_artist + " - " + (retry ? album : albm) + " " + auto_corr + " " + fn); if (!retry && name.alb_strip && album != albm) {retry = true; return this.Search(alb_artist, album, rev, path, fn, albm);} return p.trace("last.fm album cover: " + album + " / " + alb_artist + ": not found", true);}
                var pth = data[p.imgRevHQ || !rev_img ? 4 : 3]["#text"]; 
                if (pth && (p.imgRevHQ || !rev_img)) {var pthSplit = pth.split("/"); pthSplit.splice(pthSplit.length - 2, 1); pth = pthSplit.join("/");} if (!pth) {update(alb_artist + " - " + (retry ? album : albm) + " " + auto_corr + " " + fn); if (!retry && name.alb_strip && album != albm) {retry = true; return this.Search(alb_artist, album, rev, path, fn, albm);} return p.trace("last.fm album cover: " + album + " / " + alb_artist + ": not found", true);} timer.decelerating(true);
                p.buildFullPth(path); ui.run("cscript //nologo \"" + fb.ProfilePath + "yttm\\foo_lastfm_img.vbs\" \"" + pth + "\" \"" + fn + pth.slice(-4) + "\"", 0);
            }
        }
    }
}
if (p.server) var serv = new server();
timer.reset(timer.zSearch, timer.zSearchi); timer.zSearch = window.SetTimeout(function() {if (p.server) serv.fetch(false, [0, false], [0, false]); timer.zSearch = false;}, 3000);

if (!window.GetProperty("SYSTEM.Software Notice Checked", false)) fb.ShowPopupMessage("THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.", "Biography"); window.SetProperty("SYSTEM.Software Notice Checked", true); window.SetProperty(" Heading Style Reg-0 Bold-1 Italic-2 BoldItalic-3 U-line-4", null); window.SetProperty(" Layout Image Size 0-1", null); window.SetProperty(" Title Style Reg-0 Bold-1 Italic-2 BoldItalic-3 U-line-4", null); window.SetProperty("SYSTEM.Colour Update", null); window.SetProperty("SYSTEM.Heading Update", null);